Skip to main content
CC Safety Net hooks into your AI agent’s tool execution pipeline so it runs before any shell command executes. For most agents this is a PreToolUse hook; the exact mechanism varies by agent (Claude Code and Kimi Code use a PreToolUse hook on the Bash tool, Gemini CLI uses a BeforeTool hook on run_shell_command, Copilot CLI uses a preToolUse hook, and Pi loads CC Safety Net as an in-process extension). See Integration Architecture for the per-agent details. Rather than maintaining a list of forbidden strings, CC Safety Net parses each command into its components and reasons about intent. This page walks through exactly what happens between the moment your agent builds a command and when (or whether) that command runs.

The Hook Pipeline

1

Agent prepares a Bash command

Your AI agent constructs a shell command to execute — for example, git reset --hard — and passes it to the Bash tool.
2

PreToolUse hook fires

Before the Bash tool executes anything, CC Safety Net intercepts the call. This happens at the hook layer, which runs before the permission system and before the OS ever sees the command.
3

Semantic analysis

CC Safety Net parses the command into its components — executable, subcommand, flags, and arguments — and analyzes the intent of the operation. See Semantic Analysis below for details.
4

Decision returned

If the command is determined to be destructive, the agent receives a BLOCKED response with a human-readable reason explaining what the command does and what to do instead. If the command is safe, it is allowed through and executes normally.

Semantic Analysis

CC Safety Net uses semantic analysis rather than simple string matching. This distinction matters in practice. When a command arrives, it is parsed into its structural components:
  • Executable — the base program (git, rm, find, etc.)
  • Subcommand — the operation being requested (checkout, reset, push, etc.)
  • Flags — options that modify behavior (--hard, -f, -r, etc.)
  • Arguments — the targets the command acts on (file paths, branch names, refs, etc.)
With this parsed representation, CC Safety Net reasons about what the command will do, not just what it looks like. Consider two commands that share the same base:
CommandIntentOutcome
git checkout -b featureCreates a new branchAllowed
git checkout -- fileDiscards uncommitted changes in a fileBlocked
Both start with git checkout. A pattern-matching approach either blocks both or neither. Semantic analysis distinguishes them and makes the right call in each case — protecting you from accidental data loss without blocking everyday workflows.

Shell Wrapper Detection

Wrapping a destructive command in a shell invocation doesn’t hide it from CC Safety Net. Shell wrappers like bash -c '...' are recursively unwrapped and the inner command is subjected to the same semantic analysis. This unwrapping goes up to 10 levels deep.
bash -c 'git reset --hard'    # → analyzed → BLOCKED
sh -lc 'rm -rf /'             # → analyzed → BLOCKED
This means an agent cannot bypass protection simply by embedding a blocked command inside a shell invocation.

Interpreter One-Liner Detection

Destructive commands can also be hidden inside interpreter one-liners. By default, CC Safety Net extracts the code passed to an interpreter’s -c or -e flag — for python, python2, python3, node, ruby, and perl — and scans it for embedded destructive operations:
python -c 'import os; os.system("rm -rf /")'  # BLOCKED
If you want stricter behavior, set CC_SAFETY_NET_PARANOID_INTERPRETERS=1 to block all interpreter one-liners outright — regardless of their content.

Block Output Format

When CC Safety Net blocks a command, the agent receives a structured response as the tool result. A typical block message looks like this:
BLOCKED by CC Safety Net

Reason: git checkout -- discards uncommitted changes permanently. Use 'git stash' first.

Command: git checkout -- src/main.py

If this operation is truly needed, ask the user for explicit permission and have them run the command manually.
The agent reads this as the tool response and typically surfaces the explanation to you. The message tells the agent what went wrong, why it’s dangerous, and how to proceed safely — either by using a safer alternative or by asking you to run the command manually with explicit intent.

Audit Logging

Blocked commands are written to a structured log file for later review:
~/.cc-safety-net/logs/<session_id>.jsonl
Each entry in the log is a JSON object on its own line:
{"ts": "2025-01-15T10:30:00Z", "decision": "deny", "command": "git reset --hard", "segment": "git reset --hard", "reason": "...", "cwd": "/path/to/project"}
FieldDescription
tsISO 8601 timestamp of when the command was handled
decisionThe decision CC Safety Net made: deny (blocked) or allow (permitted)
commandThe full command string as received, truncated to 300 characters
segmentThe specific segment that triggered the block, truncated to 300 characters (may differ for wrapped commands)
reasonThe human-readable reason for blocking
cwdThe working directory at the time of the call
A few details worth knowing:
  • Denied commands are always logged when a session id is available; allowed commands are logged only when CC_SAFETY_NET_DEBUG=1 is set, to keep the log focused on interventions.
  • Commands blocked because the analyzer itself failed (the fail-closed safety net) are not written to the log.
  • Nothing is written when there is no session id available.
  • The doctor command summarizes this log as its Recent Activity check (blocked commands from the last 7 days).
Sensitive data (tokens, passwords, API keys) in log entries is automatically redacted before they are written to disk. See the audit log reference for the full redaction scope.

Secret Redaction

Block messages and log entries both go through automatic secret redaction before being surfaced to the agent or written to disk. This ensures that if a destructive command happens to include a token, credential, or API key in its arguments, that sensitive data is never exposed in agent responses or audit logs.

Known Limitations

CC Safety Net analyzes the command string your agent attempts to run. A few cases are out of scope or not yet handled:
  • Transparent command proxies — A tool that rewrites or proxies a shell command before it runs (for example rtk git reset --hard) can bypass analysis, because CC Safety Net sees the proxy executable (rtk) rather than the underlying command. Some top-level proxied commands are caught by the fallback dangerous-text scan, but this is incomplete, and custom rules do not yet apply through proxies. Work is tracked to add a transparent-proxy normalization layer.
  • Behavior inside binaries — If a command does not visibly contain a destructive operation (for example some-tool --task destructive-cleanup), command-string analysis cannot infer it. CC Safety Net does not and cannot inspect what arbitrary binaries do at runtime — use sandboxing for that threat.
  • Reads and network — CC Safety Net has no read-protection or network layer. It does not stop an agent from reading sensitive files or exfiltrating data. See vs Sandboxing.
If you believe a destructive command slipped through, run npx cc-safety-net explain "<command>" to see the analysis, and report genuine bypasses as described in the security policy.