Skip to main content
CC Safety Net is a pre-execution hook. It receives each shell command and file operation your coding agent is about to run, checks it on your machine, and returns allow or block before the operation reaches the operating system. A blocked call never runs, and the agent gets a message telling it why and what to do instead.

Does CC Safety Net use an LLM?

No. A local, rule-based parser makes every decision. It parses the command into its executable, subcommand, flags, and arguments, then applies fixed rules. The same command, working directory, and configuration always get the same decision. Nothing is sent to a model or over the network, and no prompt wording can turn a block into an allow.

The lifecycle of one tool call

1

Your agent prepares a tool call

The agent prepares a shell command such as git reset --hard, or a file write, edit, search, or patch, and hands it to its tool layer.
2

The integration intercepts it

CC Safety Net’s integration for that agent receives the call before the tool executes. How it receives the call depends on the agent. See Integration models.
3

CC Safety Net checks the operation

CC Safety Net parses the input once and runs the checks in What gets checked, in order.
4

An allow or a block comes back

An allowed call executes normally. A blocked call never runs, and the agent receives the block message as the tool result.
5

The decision is logged

The decision goes to the local audit log.

Integration models

CC Safety Net supports sixteen agents through four integration models. Every model runs the same checks and reaches the same decision for the same call. Each agent’s page under Installation lists the tools it protects and where its configuration lives. To call the same check from your own Node.js program, see the Library API.

What gets checked, in order

Every tool call runs through the same stages, in this order:
  1. Bounded input extraction. CC Safety Net reads the command out of the tool input under limits on depth, field count, and size. It blocks input past a limit.
  2. A single parse. CC Safety Net parses the command once, and every later stage reuses the result. It blocks input that exhausts a parser budget at every safety level.
  3. Policy-file protection. CC Safety Net blocks anything that would modify or delete its own policy.json, its directory, or an ancestor.
  4. Git-metadata protection. CC Safety Net blocks anything that would delete, move, overwrite, or patch your repository’s .git metadata or hooks directory, including from inside the working directory.
  5. Configuration load. CC Safety Net resolves your policy, rulebooks, and safety level.
  6. Sensitive-path protection. CC Safety Net checks commands, paths, searches, and patches against built-in sensitive locations (.env, ~/.ssh, cloud and coding-CLI credential files) and any deny paths you configured.
  7. Destructive-command analysis. CC Safety Net splits the command into segments and unwraps wrappers and interpreters. The matching analyzer then classifies each segment. Analyzers cover git, rm, Remove-Item, find, xargs, parallel, device commands, and custom rules.
Steps 3 and 4 run before step 5, so no configuration can weaken them. Step 6 follows your policy, so you can turn it off or extend it with your own deny paths.

What the analyzer sees through

Hiding a command inside another one does not get it past step 7:
  • Wrappers and interpreters. The analyzer unwraps sh -c, bash -c, sudo, env, and python -c or node -e one-liners and analyzes the inner command, up to 10 levels deep. Deeper nesting is blocked. See Shell wrappers and interpreter one-liners.
  • cd within one command. The analyzer judges cd dir && rm -rf x in dir. A cd the analyzer cannot resolve makes later targets unverifiable. See Filesystem commands.
  • Shell functions. The analyzer checks a function body where the function is called, so cleanup() { rm -rf ../outside; }; cleanup blocks. A definition that is never called is allowed. See Filesystem commands.
  • Heredocs. cat > note.md <<'EOF' writes data and is allowed whatever the body says. A heredoc a shell runs as its program, as in bash <<'EOF', is analyzed command by command. See Heredocs in strict and paranoid.
  • Shell scripts. The analyzer reads the script behind sh x.sh, source x.sh, and ./x.sh, whether a heredoc in the same command wrote it or it was already on disk, and names the file and line in the block reason. Interpreter files such as python3 tool.py are not read. See Scripts run from a file.
  • Compound commands. The analyzer checks commands inside if, while, until, and { …; } bodies like top-level commands, so if true; then rm -rf ~; fi blocks.
  • Dynamic targets. A target built from a variable or substitution, such as rm -rf "$target", cannot be verified before it runs. Standard allows it, and strict and paranoid block it. See Filesystem commands.

Why intent, not string matching

CC Safety Net decides on what a command does. Two commands with the same first words can get different outcomes: Both begin with git checkout, so a prefix rule cannot tell them apart without repeating Git’s option logic. Parsing the command also catches reordered flags (rm -r -f /), shell wrappers (sh -c "rm -rf /"), and interpreter one-liners (python -c 'import os; os.system("rm -rf /")'). Blocked and allowed commands lists what is stopped and what is not.

What a block looks like

The agent receives the block message as the tool result:
The Rule: line gives the id of the rule or fixed denial that blocked the call. Only a hook call whose input is missing or is not valid JSON is blocked without one. CC Safety Net shortens command and segment text and redacts secrets from the whole message. These lines appear only when they apply: A block does not end the agent session. The rule’s intent selects the closing instruction, which sends the agent back to its task instead of retrying variants: The block itself does not depend on the agent following the instruction, because the command never runs.

When the message asks instead of blocking

In Claude Code, a command that standard mode could not verify reaches you as a permission prompt instead of a block. The message keeps the same fields and changes the first and last lines:
The closing line replaces the intent instruction, because you decide this one rather than the agent. The audit log records the call as a denial either way. When Claude Code asks you instead of blocking lists which denials can ask and in which permission modes.

The audit record

CC Safety Net records every denial, and allowed command decisions by default, in a local audit log. Read it with npx cc-safety-net logs. The audit log reference covers its location, fields, retention, and redaction.

When a decision surprises you

1

Ask why

npx cc-safety-net explain "<command>" replays the analysis and shows which rule matched and why. Add --json for the structured trace.
2

Check that protection is in force

npx cc-safety-net status prints ready or degraded. degraded means a configuration source was rejected and a fallback is in force. See status for the output and Configuration recovery to repair the source.
3

Adjust or report

If the block is correct but too strict for your workflow, change your safety mode or add a per-rule override. If a safe command is blocked or a destructive one was not, see Troubleshooting and the security policy for where to report it.

What CC Safety Net does not cover

CC Safety Net checks the tool call your agent attempts. It cannot see what an arbitrary binary does once it runs, commands sent through an opaque proxy, or network activity. It is not an OS sandbox or a privilege boundary, and it does not protect commands that bypass an installed integration. See Known limitations for the full list and mitigations.
Last modified on October 27, 2026