Skip to main content
CC Safety Net sits between an untrusted command source, such as an AI coding agent, and the execution environment. This page documents the trust boundaries, safety-level guarantees, configuration failure handling, secret protection, and attack surface. To report a vulnerability, see the security policy. CC Safety Net is a best-effort, static pre-execution policy gate for supported coding-agent tool calls. It is not an operating-system sandbox, a privilege boundary, or protection for commands that bypass an installed integration.

Trust boundaries

Primary boundary: command source to execution environment

The core trust boundary sits between the AI coding agent and the host shell. CC Safety Net is the gatekeeper.
  • Untrusted side — command strings generated by AI agents. These are treated as potentially hostile because agents can be manipulated via prompt injection, confused context, or adversarial instructions into producing destructive commands.
  • Execution side — the host shell where commands would execute.
Every command that reaches the shell tool on a supported platform flows through the analysis engine before it is allowed to run. If analysis returns a block reason, the command is denied. The boundary stops at supported tool names and supported shapes. Adapters grant command-execution capability only to exact, integration-specific tool names; unknown tools keep conservative policy-file, Git-metadata, and sensitive-path inspection but their text is never treated as a shell command. Commands that bypass an installed integration entirely are outside the boundary.

Secondary boundaries

Four secondary boundaries cross into CC Safety Net from an external source. Each one is validated before it can influence analysis.

What each safety level guarantees

Standard, strict, and paranoid are presets that supply defaults for three capabilities: fail_closed, paranoid_rm, and paranoid_interpreters. The guarantee is not the same at every level.
Standard mode is not adversarial-grade. Dynamic rm -rf targets are not categorically blocked in standard — rm -rf "$target" is allowed there and blocked only in strict or paranoid. When commands may come from prompt injection or another adversarial context, strict or paranoid is required.
While secret protection is enabled, safety levels do not relax matched sensitive content access or user-configured deny paths and their descendants. A configured secret_protection.allow_paths entry can exempt a literal file or directory tree from non-CLI built-in secret rules; deny paths and secret.cli.* rules still win. Catastrophic protections are always enforced. These include recursive deletion of root or the user’s home directory, destructive changes to protected Git metadata, and destructive changes to the canonical user policy.json.

Configuration recovery boundary

Configuration is a trust boundary, not a kill switch. Invalid configuration resolves to one of two runtime states and never denies ordinary work merely for being invalid.
  • ready — every active source validated.
  • degraded — a candidate source was rejected and something safe is enforced in its place: an unverifiable rule source is dropped so it contributes no rules, a drifted or invalid local rulebook keeps its digest-verified cache, a duplicate rulebook name keeps the first claim, and an unreadable policy file falls back to the salvaged policy or to built-in protective defaults.
The rejected candidate is never treated as active. Dropping a source removes the denials that source contributed, which is a real reduction in enforcement relative to your configured policy — that reduction is reported on every surface rather than presented as security-neutral. What dropping cannot do is weaken a built-in rule: rulebooks contribute only blocking rules, and ignoring an unreadable rule.json restores the built-ins its overrides would have disabled. One exception is scoped and documented — transparent_wrappers lives in rule.json, so an unreadable rule.json narrows which wrapped commands built-in analysis unwraps for that scope. No command or path is allowlisted in return, because nothing is denied for being unconfigurable. Policy-file protection and Git-metadata protection are evaluated before the configuration snapshot is loaded, so they apply identically in both states and carry no configuration metadata. The complete contract — every failure row, the fallback it produces, and the recovery commands — lives in Configuration recovery.

Fail-closed enforcement

Fail-closed applies to that one tool call when analysis itself cannot complete: an unexpected analyzer failure, an input that cannot be parsed, or a resource limit reached. It is not a description of what happens to invalid configuration.
1

Hook entry points

The hook adapter wraps the analysis call in a try/catch. If analysis throws, the hook emits a deny decision with a “failed closed” reason instead of letting the command proceed. This applies to every stdin-based hook agent (Antigravity CLI, Claude Code, Cursor, Gemini CLI, GitHub Copilot CLI, Kimi Code).
2

Plugin and extension entry points

The Amp Code, OpenCode, OpenClaw, and Pi in-process integrations apply the same pattern — analysis errors are caught and re-surfaced as block messages so the platform treats them as denied commands. Codex is installed as a plugin but runs the shared stdin hook entry point, so it is covered by the step above. Hermes Agent layers the two: its managed Python plugin invokes that same stdin hook (cc-safety-net hook --hermes-agent), and the plugin itself blocks the call whenever analysis cannot complete — a missing npx, a working directory or Hermes session record it cannot resolve, a spawn failure, the 30-second timeout, a non-zero analyzer exit, or output it cannot read. See Integration architecture for which model each agent uses.
3

Malformed or oversized tool input

Untrusted recursive tool input is bounded to 64 object levels, 10,000 visited values, 10,000 own keys, 1 MiB per string, and 4 MiB of aggregate string data; hook stdin is capped at 8 MiB of raw bytes. Exceeding any boundary denies the call.
4

Parser resource exhaustion

Input beyond 131,072 UTF-16 code units, more than 16,384 words, or nesting beyond 64 levels is denied rather than analyzed incompletely. A separate budget of 16,384 derived tokens bounds the work that nested and embedded commands add after the initial parse — see Parsers and the runtime dependency surface. Both apply in every safety level, standard included.
5

Strict mode

Strict mode extends fail-closed to commands the shell parser cannot safely tokenize, so unparseable input is blocked rather than passed through. Standard mode allows safe-looking unparseable text.
Invalid configuration is deliberately not in this list. A rejected rule source is dropped and an unreadable policy file falls back to protective defaults, so ordinary work continues — see Configuration recovery boundary.
See Design principles for the rationale.

Secret redaction

Before any command or segment text is written to the audit log or returned to the agent, it passes through automatic secret redaction. The redactor scrubs PEM private keys, database URL environment variables, generic secret-bearing env assignments, common secret HTTP headers, URL credentials, presigned-URL signature query parameters (x-amz-signature, x-goog-signature, sig, signature), and known provider token prefixes (GitHub, Slack, npm, Stripe, PyPI), plus JWTs and AWS access key IDs. Each matched value is replaced with <redacted>. Redaction is conservative and pattern-based — it reduces the risk of leaking secrets that happen to appear in a command’s arguments, but it is bounded to recognized credential shapes. Absolute filesystem paths, project and directory names, hostnames, IP addresses, usernames, and any credential whose format is not on the pattern list are retained verbatim. New secret formats emerge regularly, so avoid piping real credentials through commands an agent runs. See the Audit log reference for the full redaction scope. The same bound applies to cc-safety-net explain: a real trace carries the command text you supplied, its parsed tokens, and absolute paths including your home directory. Review a trace before pasting it anywhere — see Explain trace.

Attack surface

The threat model enumerates the main attack surfaces and their mitigations. Network-level attacks and attacks on the agent platform itself are out of scope — CC Safety Net makes no network requests during command analysis and has no network layer. Resource exhaustion is bounded rather than mitigated by containment: input past the parser or tool-input limits is denied instead of analyzed incompletely.

Disclosure classification

The security policy defines the full reporting process. Use this table to select the report type. Report only the command shape for a coverage gap. Do not include a ready-to-paste weaponized prompt-injection payload. See the security policy for both submission channels.
Last modified on August 18, 2026