All pages
Guides
How do I stop Claude Code from running dangerous commands?
Claude Code's permission rules and PreToolUse hooks, what they leave open, and where a rule outside the agent and a kernel jail around each command help.
Start with what Claude Code already gives you. It is free, it is in the product, and for one developer on one laptop it may be enough.
What Claude Code does on its own#
Permission rules. In settings.json, list what Claude may run without asking, what it must ask about, and what it may never run. Deny rules take precedence over the other two.
{
"permissions": {
"deny": ["Bash(rm -rf:*)", "Bash(git push --force:*)", "Read(./.env)", "Read(./secrets/**)"],
"ask": ["Bash(git push:*)"],
"allow": ["Bash(npm run test:*)"]
}
}Permission modes. In the default mode Claude asks for permission before it runs most shell commands. Keep it that way for anything you have not thought through; see What happens when developers run agents with permission prompts off?
PreToolUse hooks. A hook is a program Claude Code runs before each tool call, with the call as JSON on standard input. A command hook that exits with status 2 blocks the call, and what it writes to standard error is shown to Claude as the reason:
#!/bin/sh
cmd=$(jq -r '.tool_input.command // ""')
case "$cmd" in
*"rm -rf /"*|*"git push --force"*)
echo "Blocked by local policy: $cmd" >&2
exit 2 ;;
esac
exit 0Register it under hooks.PreToolUse with the matcher Bash. A hook can also answer with JSON to allow, deny or ask.
Its own sandbox. Claude Code can run its shell commands, and the processes they start, inside an operating-system sandbox that limits which files and network hosts they can reach. It is off by default; turn it on with /sandbox. It runs on macOS, Linux and WSL2.
Managed settings. A file your administrators deploy, such as /Library/Application Support/ClaudeCode/managed-settings.json on a Mac, takes precedence over user and project settings, so developers cannot remove the rules it sets.
Anthropic documents all of these in Configure permissions, with hooks and the sandbox linked from there.
What those leave open#
- Matching text is not knowing what runs.
Bash(rm -rf:*)does not matchfind . -delete, a script that deletes, orpython -cdoing the same. Claude Code's own documentation warns that patterns which try to constrain a command's arguments are easy to get around. - A command that is allowed can start other programs. A rule judges the command line, not what runs once it starts. Claude Code's sandbox limits what those programs reach, but only while it is turned on, and it does not cover Claude's own file tools or MCP servers.
- A hook is cooperative. The runtime calls it and honours its answer. A runtime that skips its hooks, or a user who removes them, is outside its reach.
- Each machine is on its own. Rules and hook scripts live in each person's files. Nothing tells you what was blocked across a team, or whether the rules are still in place.
- Nothing knows the session. A pattern cannot say "no network once this session has read a web page."
Where Golem fits#
Golem adds three layers on top of Claude Code's own settings, not instead of them.
Rules decided outside the agent. Golem's PreToolUse hook sends every call to the Golem agent on the same machine, which checks it against your workspace's rules, written as a sentence or in CEL over fields such as entry.bash_command_text and entry.session_tainted. The decision is made on the machine, with no model and no network hop. A built-in rule blocks catastrophic commands (rm -rf against / or a home directory, dd, mkfs or shred to a raw disk, a fork bomb) from the first install. A refused call names its rule and carries a decision id such as gd_3f9a1c07b2e4d815, which the user can quote to ask for an exception with golem exception. See Block, hold and contain.
A person in front of risky calls. A rule at Ask shows Claude Code's own approval prompt with Golem's reason, in every permission mode, bypassPermissions included.
A kernel jail around every shell command. On macOS, Golem points Claude Code's shell at its own, which applies a macOS sandbox profile to the shell process before the command starts, so everything the command starts inherits it. A jailed command cannot read private keys, shell history or ~/.netrc, cannot write shell profiles, ~/.ssh, ~/Library/LaunchAgents or Claude Code's settings and hooks, and does not see environment variables whose names look like secrets. A rule can also lock a session down after a match: no network, no credentials, and writes only inside the repository. See The shell jail.
Every call, refusal and jail denial is signed into a record the agent cannot edit.
What Golem does not do here#
- The shell jail is macOS only and Claude Code only. On Linux and Windows, and for other agents, the rules apply but nothing wraps the command.
- Claude Code's Read, Write and Edit tools do not go through a shell. Rules check them; the jail does not.
- If the Golem agent is down, or does not answer within the hook's 45-second timeout, Claude Code runs the call. On a Mac the jail keeps a baseline that still denies credential stores and persistence writes.
- Commands you type in your own terminal are not checked.
Read next#
- Claude Code: exactly what Golem adds to your settings
- Rules and CEL: writing a rule and testing it on 30 days of your own traffic
- Shell jail and sandbox
- Limits