charmbracelet/crush · error
command is not allowed for security reasons: %q
Error message
command is not allowed for security reasons: %q
What it means
This is the command-blocking middleware built from blockFuncs in run.go. For each executed command it checks the argument list against every registered block function; if any returns true, the command is refused with "command is not allowed for security reasons: %q" before reaching the interpreter. It is an intentional policy denial, not an internal failure.
Source
Thrown at internal/shell/run.go:343
return h(ctx, args, hc.Stdin, hc.Stdout, hc.Stderr)
}
return next(ctx, args)
}
}
}
// blockHandler returns middleware that rejects commands matched by any of
// the provided [BlockFunc]s before they reach the underlying exec path.
// A nil or empty blockFuncs slice is a no-op.
func blockHandler(blockFuncs []BlockFunc) execMiddleware {
return func(next interp.ExecHandlerFunc) interp.ExecHandlerFunc {
return func(ctx context.Context, args []string) error {
if len(args) == 0 {
return next(ctx, args)
}
for _, blockFunc := range blockFuncs {
if blockFunc(args) {
return fmt.Errorf("command is not allowed for security reasons: %q", args[0])
}
}
return next(ctx, args)
}
}
}
View on GitHub (pinned to 7944b8e522)
Solutions
- Use a command permitted by the project's security policy instead of the blocked one.
- If the block is too broad, adjust the BlockFuncs predicates to match only genuinely dangerous argument patterns.
- If the command is safe and required, add it to the allow-list/configure permissions so the blocking predicate no longer matches.
- Check args[0] in the message: it names the exact blocked command token.
Example fix
// before
block := func(args []string) bool { return args[0] == "rm" }
// after — allow safe variants
block := func(args []string) bool {
return args[0] == "rm" && !slices.Contains(args, "-rf")
} Defensive patterns
Strategy: try-catch
Validate before calling
func isBlocked(cmd string, blockFuncs []func([]string) bool) bool {
args := strings.Fields(cmd)
if len(args) == 0 { return false }
for _, bf := range blockFuncs { if bf(args) { return true } }
return false
} Try / catch
err := shell.Run(ctx, opts)
if err != nil && strings.Contains(err.Error(), "not allowed for security reasons") {
// treat as user-facing policy denial: show message, do not retry
} Prevention
- Pre-check commands against your block predicates before submitting them to the agent.
- Keep deny lists narrow (match exact args[0] plus dangerous flags) to avoid false positives.
- Document permitted commands for users so denied commands are expected.
- Log blocked attempts with the full args for auditing.
When it happens
Trigger: Calling shell.Run with RunOpts.BlockFuncs containing a predicate that matches the command (e.g. blocking 'rm', 'curl', or commands whose first arg is on a deny list). Empty argument lists fall through to next, so only non-empty commands can be blocked.
Common situations: Users of Crush running a command the project's permission policy disallows; tests (TestCommandBlocking, TestArgumentsBlocker, TestCommandsBlocker) verifying deny lists; misconfigured allow-lists that accidentally match benign commands like 'git push'.
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/9fdc27a22e2dc63f.
Report an issue: GitHub.