Skip to main content
CC Safety Net resolves protection into three safety levels: standard, strict, and paranoid. Each level is a preset that expands into the same three capabilities. A level is shorthand, not a separate code path. Set the level with safety.level in policy.json or the CC_SAFETY_NET_LEVEL environment variable. The higher value becomes the effective base level. The individual toggles on this page set one capability on top of that base. CC Safety Net reports any combination that does not match one of the three presets as the effective level custom.
Mode and debug flags use CC_SAFETY_NET_* environment variables. Older SAFETY_NET_* names (without the CC_ prefix) are also accepted for strict, paranoid, paranoid-rm, paranoid-interpreters, and worktree toggles. See Environment for the full list and for the exact precedence between policy and environment, and Policy for safety.level and safety.overrides.

Default mode

Default mode is the standard safety level. You do not need environment variables to start, and CC Safety Net protects against the built-in destructive git and filesystem patterns. Start here unless you need the stricter checks below. Some failures are handled the same way at every level:
  • Invalid hook input JSON is always blocked (fail-closed), in every mode.
  • If the analyzer itself throws an unexpected error, the command is always blocked (fail-closed) with a “failed closed” reason, in every mode.
  • A command that exceeds the parser’s recursion or structural validation limits is always blocked, in every mode. These resource-exhaustion bounds are not relaxed by the standard level.
Where standard differs is unparseable and unverifiable input:
  • If a command cannot be tokenized by the shell parser (for example, an unterminated quote), CC Safety Net runs a fallback text scan for known-dangerous patterns. If the scan matches, the command is blocked; if it does not match, the command is allowed through. So echo 'unterminated is allowed, while git reset --hard 'unterminated is still blocked by the heuristic scan.
  • Dynamic recursive-delete targets are not categorically blocked in standard. rm -rf "$target" is allowed here and blocked only once the fail-closed capability is on.
Standard also intentionally allows dynamic executables, command structure assembled through substitution, other unverifiable recursive-delete targets, standalone metadata-only checks of built-in sensitive paths, and eval/source of a single fully literal local generator command such as eval "$(ssh-agent -s)". These are deliberate trade-offs: standard is best-effort against adversarial or dynamic input. Use strict or paranoid when commands may come from prompt injection or another adversarial context. Standard never relaxes sensitive content access, user-configured deny paths and their descendants, or the catastrophic protections (root and home recursive deletion, Git metadata, and the canonical policy.json).

Strict mode (CC_SAFETY_NET_STRICT=1)

Strict mode turns on the fail_closed capability. It tightens five distinct things. Unparseable commands are the first:
  • Unparseable commands are blocked. CC Safety Net denies any command the parser cannot split into tokens, even when the fallback text scan finds no dangerous pattern. The reason is “Command could not be safely analyzed (strict mode)”. echo 'unterminated is allowed in standard and blocked here.
  • Heredocs fail closed. A command containing a heredoc is denied unless it has exactly one unexpanded heredoc, on stdin, no other input redirection, and a consumer that is a literal cat, tee, git apply, git commit, gh pr create, or gh issue create. A heredoc is unexpanded when the delimiter is quoted (<<'EOF'), or when the delimiter is unquoted and its body contains no $, backtick, or backslash. So python3 - <<'PY' and a cat <<EOF whose body mentions $HOME are denied here, while git commit -F - <<'EOF' and a plain-text cat <<EOF still pass. See Heredoc analysis for the exact gate.
  • Unverifiable destructive targets are blocked by the five rules listed below.
  • Metadata-only sensitive-path discovery is blocked. test -f ~/.ssh/id_rsa and find ~/.ssh -type f are allowed in standard and denied in strict.
  • The standard-only inline-data relaxation is disabled. In standard, a sensitive path literal inside an interpreter’s inline code is inert data unless the code names a filesystem, command-execution, or eval marker. That covers every code interpreter except the POSIX shells, whose inline code the guard walks as shell instead. Strict removes the allowance and scans inside literal text as well. See Secret protection.
These five rules activate only when fail_closed is on: Invalid hook input JSON, analyzer exceptions, and parser resource-limit failures already fail closed in every mode. Strict does not add those checks.

Enable the strict safety level

The legacy toggle CC_SAFETY_NET_STRICT=1 sets the same capability and is still accepted:

When to use the strict safety level

Enable strict mode when commands can come from an adversarial or untrusted context. You can also use it when you want maximum protection and can accept occasional false positives for unusual command syntax.
Individual strict-tier rules can be turned off through destructive_command_protection.overrides in policy.json, and any strict-tier rule can be force-enabled under standard with an "on" override. Strict is still strict for fail-closed outcomes that have no destructive-command rule id, such as parser fail-closed and sensitive-path outcomes.

Paranoid mode (CC_SAFETY_NET_PARANOID=1)

The paranoid level is strict plus two capabilities, paranoid_rm and paranoid_interpreters. These checks may disrupt some normal workflows, so they are opt-in. You can select the whole level or activate individual capabilities. A level with only one of them has the effective level custom.

rm check (CC_SAFETY_NET_PARANOID_RM=1)

By default, CC Safety Net allows rm -rf within the current working directory because it assumes that deletion inside your project root is intentional. The paranoid rm check blocks non-temp recursive forced removal even inside the current working directory. rm -rf ./cache matches rm.recursive-force-paranoid. The PowerShell equivalent Remove-Item ./cache -Recurse -Force matches powershell.remove-item-recursive-force-paranoid. Temp targets and directories listed in destructive_command_protection.allow_paths are still allowed under this check.

Interpreter one-liners (CC_SAFETY_NET_PARANOID_INTERPRETERS=1)

Interpreter one-liners can hide destructive commands inside strings that are hard to inspect statically. Below paranoid, only a one-liner whose body contains a dangerous command is blocked (rule interpreter.dangerous-command). With this check enabled, every interpreter one-liner is blocked regardless of its content, via interpreter.one-liner-paranoid:
  • python -c '...' (also python3 and python2)
  • node -e '...'
  • ruby -e '...'
  • perl -e '...'
So python -c "print(1)" is allowed in standard and strict, and blocked here.

Enable the paranoid safety level

Enable both paranoid checks without fail-closed behavior

Enable individual paranoid checks

Setting CC_SAFETY_NET_PARANOID=1 is equivalent to enabling both CC_SAFETY_NET_PARANOID_RM=1 and CC_SAFETY_NET_PARANOID_INTERPRETERS=1. It does not turn on fail_closed, so on top of the default standard level it produces the effective level custom rather than paranoid. Use CC_SAFETY_NET_LEVEL=paranoid (or safety.level: "paranoid") when you want the full preset.

Worktree mode (CC_SAFETY_NET_WORKTREE=1)

Linked Git worktrees can provide isolated workspaces. Worktree mode relaxes selected local-discard rules only when CC Safety Net confirms that the current working directory is inside a linked worktree.

Enable worktree mode

You can also set workflow.worktree_mode: true in policy.json. CC Safety Net combines the two settings as a logical OR. Either one enables worktree mode.

Commands allowed in a linked worktree

When worktree mode is active and the cwd is confirmed to be a linked worktree, the following commands are permitted:
  • git restore <file> and git restore --worktree <file>
  • git checkout -- <file>, git checkout <ref> -- <file>, git checkout --force, and ambiguous multi-positional checkout forms
  • git reset --hard and git reset --merge
  • git clean -f (and combined short flags like -fd)
  • git switch --discard-changes and git switch -f / --force

Commands blocked in linked worktrees

These commands affect shared refs or other worktrees and are never relaxed, regardless of worktree mode:
  • git push --force affects the remote
  • git branch -D force-deletes a branch that is shared across worktrees
  • git stash drop / git stash clear changes the stash shared across worktrees
  • git worktree remove --force could delete another worktree

Linked-worktree detection

Worktree detection is fail-closed: if CC Safety Net cannot positively identify the cwd as a linked worktree, the stricter default rules remain in effect. Specifically:
  • A linked worktree is identified by a .git file (not a directory) whose resolved git directory contains a commondir file. Main worktrees and submodules are not relaxed.
  • The cwd walk uses realpath so symlinked paths resolve correctly.
  • git -C <path> arguments are honored; unresolved targets keep the command blocked.
  • Relaxation is disabled if --git-dir / --work-tree is passed, or if GIT_DIR / GIT_WORK_TREE / GIT_COMMON_DIR / GIT_INDEX_FILE is set in the environment.
  • Certain local discards are never relaxed even inside a confirmed worktree: commands with dynamic arguments containing $, *, ?, or [; forced branch resets (git checkout -B/-Bf or git switch -C/-Cf with -f or --discard-changes); git clean with more than one -f; and any command using --recurse-submodules (or a recursive-submodule config).

Safety level summary

Worktree mode is independent of the level: it relaxes local-discard rules inside a confirmed linked worktree. See Environment for every variable that selects a level or forces a capability, the legacy SAFETY_NET_* aliases, and the full precedence rules between policy.json and the environment.
You can check which level is currently in effect by running npx cc-safety-net status (or npx cc-safety-net doctor for the full report), or by looking at the status line in Claude Code. See Status line for setup instructions.
Last modified on September 15, 2026