Semantic analysis over wildcard patterns
AI coding agents support deny rules with wildcard matching, such as a wildcard rule forgit reset --hard. Wildcard patterns compare the raw command string against a pattern, so any variation in spacing, flag order, or command wrapping can cause a block to silently fail. Reordering flags (rm -r -f /), wrapping in a shell (sh -c "rm -rf /"), or hiding behind an interpreter all bypass string matching.
CC Safety Net instead parses each command into tokens, splits it into segments by shell operators, strips wrappers and environment assignments, and then runs per-command analyzers that understand the option grammar of rm, git, find, xargs, and parallel. This semantic approach catches forms that wildcard matching misses, because it reasons about what the command does rather than what it looks like.
The tradeoff is complexity: the parser must handle shell syntax correctly, and each supported command needs its own analyzer. The benefit is bypass resistance for the commands that matter most. For the full pipeline, see Analysis Engine.
Fail-closed as the default
When analysis fails, config is invalid, or input cannot be parsed, CC Safety Net blocks the command. This applies at every entry point:- The hook entry point wraps analysis in a try/catch and denies with a “failed closed” reason on any thrown error.
- The OpenCode plugin and Pi extension catch analysis errors and re-surface them as block messages.
- Strict mode extends fail-closed to commands the shell parser cannot safely tokenize.
- A broken rulebook config sets a fail-closed reason that blocks every command until repaired.
A single runtime dependency
The only runtime dependency isshell-quote, used for command tokenization. This is deliberate:
- A smaller dependency tree means a smaller supply-chain attack surface.
- Shell tokenization is a well-understood problem with a mature, focused library.
- CC Safety Net runs as a short-lived process on every shell tool call, so startup time matters — fewer dependencies mean faster cold starts.
The rulebook system
Earlier versions stored custom rules as inline JSON in a single project file. CC Safety Net replaced this with a rulebook system for four reasons:- Sharing — rulebooks can be fetched from GitHub repositories and pinned with SHA-256 digests in a lockfile, so teams share blocking policy without copy-pasting JSON.
- Integrity — remote rulebook content is verified against the lockfile digest before use. Inline config had no integrity story.
- Scoping — rulebooks support separate user (global) and project scopes with distinct config directories.
- Validation — rulebook content is schema-validated and fixture-tested before it can influence a blocking decision.
Defense-in-depth, not a replacement
CC Safety Net does not claim to be a complete security solution. It is positioned as one layer in a defense-in-depth stack:- Permission deny rules offer quick, user-configurable blocks. CC Safety Net runs before the permission system, so it inspects every command regardless of how deny rules are configured.
- OS-level sandboxing restricts filesystem and network access but does not understand whether an operation is destructive within those boundaries. A
git reset --hardinside a sandboxed directory is technically safe from the sandbox’s perspective but still a footgun.
Worktree relaxation
Linked git worktrees create a usability problem: a developer working in a worktree often wants to rungit checkout -- . or git reset --hard to discard local changes in that worktree, but the default rules block these as local-discard operations.
Worktree relaxation lifts the block for local discards when all of the following hold:
- Worktree mode is enabled (
CC_SAFETY_NET_WORKTREE=1). - No git context environment override is present (for example
GIT_DIRorGIT_WORK_TREE). - The current directory is positively verified as a linked worktree — the
.gitfile, itscommondirbacklink, and theconfig.worktreesetting are all checked, so a crafted directory cannot masquerade as a worktree. - The command is not a non-relaxable local discard (dynamic arguments, recursive submodule config, forced branch resets, or
git cleanwith more than one-f).
Related pages
- Analysis Engine — how the semantic-analysis pipeline is implemented.
- Security Model — the trust boundaries and attack surface these decisions protect.
- Known Limitations — what these design choices cannot do.
- Architecture — the entry points and component layout.