# 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.

```json
{
  "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?](/guides/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:

```bash
#!/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 0
```

Register 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](https://code.claude.com/docs/en/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 match `find . -delete`, a script that deletes, or `python -c` doing 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](/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](/response).

**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](/shield#the-shell-jail).

Every call, refusal and jail denial is signed into a [record](/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](/agents/claude-code): exactly what Golem adds to your settings
- [Rules and CEL](/rules): writing a rule and testing it on 30 days of your own traffic
- [Shell jail and sandbox](/shield)
- [Limits](/limits#a-hook-is-only-as-strong-as-the-client)
