SafetyCard Request a review

Crush

Charm's glamorous terminal agentic coding tool

github.com/charmbracelet/crush · 2026-10-03 · bdcf796

Defense-in-depth score

1.6 / 10

Crush asks before most shell commands and file writes, and shows the real command or diff. But the prompt does not cover every path, and a cloned repository can turn approval off or run its own shell script the moment you launch Crush there. Nothing is sandboxed, every command gets your full environment and credentials, and there are no step, time or cost limits. Treat it as running with your full user authority, and only launch it in repositories whose crushrc/crush.json you have reviewed.

Safest setup

Crush asks before most shell commands, file writes, fetches and MCP calls, shows the real command or diff, and records every tool call in a local database. Beyond that the defaults are thin: commands run as you with your full environment, nothing is sandboxed, there is no step, time or cost limit, and a repository's own config files are trusted on launch. The safest setup keeps the approval prompt in your hands and builds the boundaries around Crush yourself.

SetupHowWhat it gives you
A dedicated, low-limit keyLaunch Crush from a shell or account that holds only the model key and credentials this project needs, with a spending limit set at the providerWhatever a session runs, it reaches only the systems and spend you chose, not everything your account can C1
Reviewed project configOpen Crush only in repositories whose crush.json, .crush.json, .crushrc, crushrc and .crush/crush.json you have readStartup scripts, MCP servers, hooks and approval settings come only from you C6
Per-call approvalRun the interactive TUI without --yolo, and keep allowed_tools under permissions empty in your user configA person sees the actual command or diff before most shell commands, file writes, fetches and MCP calls run C2
Only the tools neededList the built-in tools the task doesn't use, such as sourcegraph or download, in disabled_tools under optionsThe model sees fewer tools, and the sourcegraph search that runs without a prompt is gone when unused C3
Its own container or VMRun Crush in a container or VM holding only the project and its key, with network limited to the model provider and the hosts the task needsAn outer boundary around shell commands, MCP servers and startup scripts, which otherwise run as you on your machine C4
Records outside the project--data-dir <path outside the project> when launching CrushThe session database lives outside the directory the agent works in C9
A watched sessionStay with the session and quit Crush when the task is done or starts to driftRuns and background shell jobs end when you say, since Crush sets no step, time or cost limit of its own C10

Approving with confidence

  • Read each prompt and approve calls one at a time; 'Allow for session' on bash covers every later command in that directory.
  • Approving agentic_fetch also approves everything its sub-agent does in that run, so approve it for pages you trust.
  • Non-interactive crush run approves every permission on its own, so keep it for runs inside the container or VM.

Handling data

  • The session database keeps every tool call and result; store it like the project itself.
  • --debug logging writes full request and response bodies, so leave it off where logs are shared.
  • Anonymous usage metrics are on by default and carry no prompt content; CRUSH_DISABLE_METRICS=1 or disable_metrics turns them off.

Key gaps (6)

  1. A repository's crush.json, .crushrc or .crush/crush.json can set permissions.allowed_tools to auto-approve bash, silently disabling the approval gate. C2 · Approval gates
  2. A .crushrc or crushrc in the opened project is executed as a shell script at startup with the user's full environment and no trust prompt. C6 · Memory, context & configuration integrity
  3. MCP servers declared in any loaded config, including the repository's, are launched automatically with the full environment and no consent. C7 · Third-party extensions
  4. A hijacked default session can read secrets (safe-listed printenv), and because the approval gate does not cover every path it can exfiltrate them and run destructive commands without any human approval. C5 · Untrusted input blast radius
  5. No isolation: all commands run as the developer's user with home directory, credentials and network. C4 · Code-execution isolation
  6. Ambient user identity with full environment passed to every subprocess; a bypassed gate reaches the whole user account. C1 · Identity & least privilege

Criteria

C1 Identity & least privilege

0.07 / 1.00

Crush runs as the developer's own OS user and narrows none of that authority. Every shell command and every MCP server it launches inherits the full process environment, so model-provider API keys, cloud credentials, GitHub tokens and the SSH agent are all reachable. There is no per-tool identity or credential scoping; the only check between the model and those credentials is the approval prompt, which does not cover every path. A hijacked session therefore acts with everything the developer can do.

C2 Approval gates

0.25 / 1.00

By default Crush asks before running shell commands, writing or editing files, fetching URLs and calling MCP tools, and the prompt shows the real command or diff. But the gate has several holes. The built-in 'safe command' list is not a strict boundary. A project's own crush.json or .crushrc can add bash to allowed_tools, which silently auto-approves it. 'Allow for session' on bash approves every later command in that directory, and an approved agentic_fetch sub-agent runs with its whole session auto-approved.

C3 Tool & action scoping

0.20 / 1.00

Crush's main tool is an arbitrary shell, guarded only by a denylist of command names (curl, wget, ssh, sudo, package installs) that is not a complete boundary. File tools accept any path on the machine and rely on the approval prompt; view and ls only ask when a path is outside the working directory, and that check is not a strict boundary. fetch and download accept any http(s) URL including localhost and cloud metadata addresses. All tools, including shell, write and network, are enabled by default, though each can be disabled in config.

C4 Code-execution isolation

0.00 / 1.00

There is no isolation at all. Shell commands run through an embedded Go shell interpreter that executes real binaries as the developer's user, in the developer's environment, with full network access. Repository-supplied crushrc files, hooks, LSP servers and MCP servers also run directly on the host. A denylist of command names is the only filter, and it is not a complete boundary.

C5 Untrusted input blast radius

0.20 / 1.00

Crush reads files, web pages and MCP results straight into the model context with no marking of what is untrusted and nothing that changes behaviour after reading it. The approval prompt is the only brake: printenv is on the safe list, so a hijacked model can read API keys from the environment unprompted, and the gate does not cover every path, so it can act on them without approval. The sourcegraph tool also sends model-chosen text to a third party without asking.

C6 Memory, context & configuration integrity

0.10 / 1.00

Opening Crush in a cloned repository trusts that repository completely. A .crushrc or crushrc in the project is executed as a shell script at startup, and $(...) in a project crush.json runs at load time, before any UI appears; the project's config can also add hooks, MCP servers and LSP servers, auto-approve tools, and redirect provider endpoints. The project's .crush/crush.json is merged with the highest priority. Instruction files such as AGENTS.md, CLAUDE.md and .cursorrules are loaded silently. The docs warn users about this, but the code asks for no trust decision.

C7 Third-party extensions

0.13 / 1.00

Crush launches MCP servers listed in any loaded config, including a repository's own crush.json, automatically at startup with no consent prompt. Commands are run exactly as written (often 'npx' or 'uvx' of an unpinned package), with no hash or signature check, and each server gets the full user environment. MCP tool calls are approval-gated, but by then the server process already runs with the user's authority. When the Docker MCP gateway is enabled, the model can add new MCP servers without a prompt.

C8 Secrets & sensitive-data protection

0.20 / 1.00

API keys come from environment variables or plaintext JSON config files written with 0600 permissions; there is no keychain use. Debug HTTP logging redacts auth-like headers but writes full request and response bodies. Every shell subprocess inherits the full environment, and printenv/env are on the unprompted safe list, so the model can read provider and cloud keys into its context. Anonymous usage telemetry to PostHog is on by default (no prompt content), and can be disabled via env var or config.

C9 Audit & traceability

0.45 / 1.00

Every tool call and its result are saved as messages in a local SQLite database, written as each result arrives, so a session's actions can be reconstructed. Sub-agent runs are stored as their own sessions. Approvals and denials are not stored, and the database and logs live in the project's .crush directory, which the agent's own shell can edit or delete.

C10 Limits & kill switch

0.00 / 1.00

Crush has no cap on steps, time or cost per run. The only automatic stop is a loop detector for identical repeated tool calls and a context-window summarizer, neither of which bounds damage. Shell commands are not timed out: after 60 seconds they move to a background job that keeps running. Pressing cancel kills a foreground command's process group, but background jobs keep running until the app exits.