Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

cc-safety-net

Package Overview
Dependencies
Maintainers
1
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cc-safety-net

A coding agent CLI hook - block destructive git and filesystem commands before execution

latest
Source
npmnpm
Version
1.0.1
Version published
Weekly downloads
1.3K
37.9%
Maintainers
1
Weekly downloads
 
Created
Source

CC Safety Net

CI codecov Version Codex Claude Code Copilot CLI Gemini CLI Kimi CLI OpenCode Pi License: MIT

CC Safety Net

A Coding Agent CLI plugin that acts as a safety net, catching destructive git and filesystem commands before they execute.

Contents

Why This Exists

We learned the hard way that instructions aren't enough to keep AI agents in check. After Claude Code silently wiped out hours of progress with a single rm -rf ~/ or git checkout --, it became evident that soft rules in an CLAUDE.md or AGENTS.md file cannot replace hard technical constraints. The current approach is to use a dedicated hook to programmatically prevent agents from running destructive commands.

Why Use This Instead of Permission Deny Rules?

Claude Code's .claude/settings.json supports deny rules with wildcard matching (e.g., Bash(git reset --hard:*)). Here's how this plugin differs:

At a Glance

Permission Deny RulesCC Safety Net
SetupManual configuration requiredWorks out of the box
ParsingWildcard pattern matchingSemantic command analysis
Execution orderRuns secondRuns first (PreToolUse hook)
Shell wrappersNot handled automatically (must match wrapper forms)Recursively analyzed (up to 10 levels)
Interpreter one-linersNot handled automatically (must match interpreter forms)Detected and blocked

Permission Rules Have Known Bypass Vectors

Even with wildcard matching, Bash permission patterns are intentionally limited and can be bypassed in many ways:

Bypass MethodExample
Options before valuecurl -X GET http://evil.com bypasses Bash(curl http://evil.com:*)
Shell variablesURL=http://evil.com && curl $URL bypasses URL pattern
Flag reorderingrm -r -f / bypasses Bash(rm -rf:*)
Extra whitespacerm -rf / (double space) bypasses pattern
Shell wrapperssh -c "rm -rf /" bypasses Bash(rm:*) entirely

CC Safety Net Handles What Patterns Can't

ScenarioPermission RulesCC Safety Net
git checkout -b feature (safe)Blocked by Bash(git checkout:*)Allowed
git checkout -- file (dangerous)Blocked by Bash(git checkout:*)Blocked
rm -rf /tmp/cache (safe)Blocked by Bash(rm -rf:*)Allowed
rm -r -f / (dangerous)Allowed (flag order)Blocked
bash -c 'git reset --hard'Allowed (wrapper)Blocked
python -c 'os.system("rm -rf /")'Allowed (interpreter)Blocked

Defense in Depth

PreToolUse hooks run before the permission system. This means CC Safety Net inspects every command first, regardless of your permission configuration. Even if you misconfigure deny rules, CC Safety Net provides a fallback layer of protection.

Use both together: Permission deny rules for quick, user-configurable blocks; CC Safety Net for robust, bypass-resistant protection that works out of the box.

What About Sandboxing?

Claude Code offers native sandboxing that provides OS-level filesystem and network isolation. Here's how it compares to CC Safety Net:

Different Layers of Protection

SandboxingCC Safety Net
EnforcementOS-level (Seatbelt/bubblewrap)Application-level (PreToolUse hook)
ApproachContainment — restricts filesystem + network accessCommand analysis — blocks destructive operations
FilesystemWrites restricted (default: cwd); reads are broad by defaultOnly destructive operations blocked
NetworkDomain-based proxy filteringNone
Git awarenessNoneExplicit rules for destructive git operations
Bypass resistanceHigh — OS enforces boundariesLower — analyzes command strings only

Why Sandboxing Isn't Enough

Sandboxing restricts filesystem + network access, but it doesn't understand whether an operation is destructive within those boundaries. These commands are not blocked by the sandbox boundary:

[!NOTE] Whether they're auto-run or require confirmation depends on your sandbox mode (auto-allow vs regular permissions), and network access still depends on your allowed-domain policy. Claude Code can also retry a command outside the sandbox via dangerouslyDisableSandbox (with user permission); this can be disabled with allowUnsandboxedCommands: false.

CommandSandboxingCC Safety Net
git reset --hardAllowed (within cwd)Blocked
git checkout -- .Allowed (within cwd)Blocked
git stash clearAllowed (within cwd)Blocked
git push --forceAllowed (if remote domain is allowed)Blocked
rm -rf .Allowed (within cwd)Blocked

Sandboxing sees git reset --hard as a safe operation—it only modifies files within the current directory. But you just lost all uncommitted work.

When to Use Sandboxing Instead

Sandboxing is the better choice when your primary concern is:

  • Prompt injection attacks — Reduces exfiltration risk by restricting outbound domains (depends on your allowed-domain policy)
  • Malicious dependencies — Limits filesystem writes and network access by default (subject to your sandbox configuration)
  • Untrusted code execution — OS-level containment is stronger than pattern matching
  • Network control — CC Safety Net has no network protection

They protect against different threats:

  • Sandboxing contains blast radius — even if something goes wrong, damage is limited to cwd and approved network domains
  • CC Safety Net prevents footguns — catches git-specific mistakes that are technically "safe" from the sandbox's perspective

Running both together provides defense-in-depth. Sandboxing handles unknown threats; CC Safety Net handles known destructive patterns that sandboxing permits.

Prerequisites

  • Node.js: Version 18 or higher is required to run this plugin

Quick Start

Codex Installation

  • Enable Codex plugin hooks in ~/.codex/config.toml:
[features]
plugin_hooks = true
  • Add the marketplace:
codex plugin marketplace add kenryu42/cc-marketplace
  • Start Codex.
  • In the TUI, run /plugins.
  • Use arrow keys to select [cc-marketplace].
  • Press Enter to install the plugin.
  • run /hooks and select the safety-net PreToolUse hook and press t to trust it.

Claude Code Installation

/plugin marketplace add kenryu42/cc-marketplace
/plugin install safety-net@cc-marketplace
/reload-plugins

Claude Code Auto-Update

  • Run /plugin → Select Marketplaces → Choose cc-marketplace → Enable auto-update

Gemini CLI Installation

gemini extensions install https://github.com/kenryu42/gemini-safety-net

GitHub Copilot CLI Installation

/plugin install kenryu42/copilot-safety-net

Kimi CLI Installation

Install CC Safety Net into your Kimi CLI config:

npx -y cc-safety-net hook install --kimi-cli

OpenCode Installation

Install CC Safety Net with OpenCode's native plugin command:

opencode plugin -g cc-safety-net

[!NOTE] OpenCode can sometimes keep using a stale cached plugin version. See anomalyco/opencode#25293 for the current tracking issue.

To force OpenCode to reinstall cc-safety-net, remove its cached package and install the version you want:

rm -rf ~/.cache/opencode/packages/cc-safety-net@latest
opencode plugin -g -f cc-safety-net@latest

If you prefer pinning a specific version:

rm -rf ~/.cache/opencode/packages/cc-safety-net@latest
opencode plugin -g -f cc-safety-net@<version>

Restart OpenCode after updating so the plugin is loaded from the refreshed
cache.

Pi Installation

Install CC Safety Net with Pi's package installer:

pi install npm:cc-safety-net

Status Line Integration

CC Safety Net can display its status in Claude Code's status line, showing whether protection is active and which modes are enabled.

Add the following to your ~/.claude/settings.json:

Using Bun (recommended):

{
  "statusLine": {
    "type": "command",
    "command": "bunx cc-safety-net statusline --claude-code"
  }
}

Using Claude X:

{
  "statusLine": {
    "type": "command",
    "command": "BUN_BE_BUN=1 claude x cc-safety-net statusline --claude-code"
  }
}

[!NOTE] The claude x command is only compatible with the native version of Claude Code. If you installed via npm, please use npx or bunx instead.

Using NPM:

{
  "statusLine": {
    "type": "command",
    "command": "npx -y cc-safety-net statusline --claude-code"
  }
}

Piping with existing status line:

If you already have a status line command, you can pipe CC Safety Net at the end:

{
  "statusLine": {
    "type": "command",
    "command": "your-existing-command | bunx cc-safety-net statusline --claude-code"
  }
}

Changes take effect immediately — no restart needed.

Emoji Mode Indicators

The status line displays different emojis based on the current configuration:

StatusDisplayMeaning
Plugin disabled🛡️ CC Safety Net ❌CC Safety Net plugin is not enabled
Default mode🛡️ CC Safety Net ✅Protection active with default settings
Strict mode🛡️ CC Safety Net 🔒CC_SAFETY_NET_STRICT=1 — fail-closed on unparseable commands
Paranoid mode🛡️ CC Safety Net 👁️CC_SAFETY_NET_PARANOID=1 — all paranoid checks enabled
Paranoid RM only🛡️ CC Safety Net 🗑️CC_SAFETY_NET_PARANOID_RM=1 — blocks rm -rf even within cwd
Paranoid interpreters only🛡️ CC Safety Net 🐚CC_SAFETY_NET_PARANOID_INTERPRETERS=1 — blocks interpreter one-liners
Worktree mode🛡️ CC Safety Net 🌳CC_SAFETY_NET_WORKTREE=1 — relax local git discards inside linked worktrees
Strict + Paranoid🛡️ CC Safety Net 🔒👁️Both strict and paranoid modes enabled

Multiple mode emojis are combined when multiple environment variables are set. Mode flags use CC_SAFETY_NET_* names; legacy SAFETY_NET_* names are still accepted.

Diagnostics

Run the diagnostic command to verify your installation and troubleshoot issues:

npx cc-safety-net doctor
# or with bun
bunx cc-safety-net doctor

The doctor command checks:

CheckDescription
Hook IntegrationVerifies the plugin is properly configured for each supported platform
Self-TestRuns sample commands to confirm blocking works correctly
ConfigurationValidates custom rules in user and project configs
EnvironmentShows status of mode flags (CC_SAFETY_NET_STRICT, CC_SAFETY_NET_PARANOID, etc.; legacy SAFETY_NET_* also listed when set)
Recent ActivitySummarizes blocked commands from the last 7 days
System InfoDisplays versions of all relevant tools
Update CheckChecks if a newer version is available

Options

FlagDescription
--jsonOutput in JSON format (useful for sharing in bug reports)
--skip-update-checkSkip the npm version check

Explain (Debug Analysis)

Trace how CC Safety Net analyzes a command step-by-step. Useful for debugging why a command is blocked or allowed, or when developing custom rules.

npx cc-safety-net explain "git reset --hard"
# or with bun
bunx cc-safety-net explain "git reset --hard"

Options

FlagDescription
--jsonOutput analysis as JSON
--cwd <path>Use custom working directory for analysis

Examples

npx cc-safety-net explain "rm -rf /"
npx cc-safety-net explain --json "git checkout -- file.txt"
npx cc-safety-net explain --cwd /tmp "git status"

Commands Blocked

Command PatternWhy It's Dangerous
git checkout -- filesDiscards uncommitted changes permanently
git checkout <ref> -- <path>Overwrites working tree with ref version
git checkout <ref> <path>May overwrite working tree when Git disambiguates ref vs pathspec
git restore filesDiscards uncommitted changes
git restore --worktreeExplicitly discards working tree changes
git switch --discard-changesDiscards uncommitted changes when switching branches
git switch --force / -fDiscards uncommitted changes (force switch)
git reset --hardDestroys all uncommitted changes
git reset --mergeCan lose uncommitted changes
git clean -fRemoves untracked files permanently
git push --force / -fDestroys remote history
git branch -DForce-deletes branch without merge check
git stash dropPermanently deletes stashed changes
git stash clearDeletes ALL stashed changes
git worktree remove --forceForce-deletes worktree without checking for changes
rm -rf (destructive targets)Recursive file deletion of root, home, parent, absolute, or non-temp paths outside cwd
rm -rf / or ~ or $HOMERoot/home deletion is extremely dangerous
find ... -deletePermanently removes files matching criteria
xargs rm -rfDynamic input makes targets unpredictable
xargs <shell> -cCan execute arbitrary commands
parallel rm -rfDynamic input makes targets unpredictable
parallel <shell> -cCan execute arbitrary commands
dd writing to block devicesCan overwrite disks or partitions
mkfs on block devicesFormats disks or partitions
shredPermanently destroys file contents

Commands Allowed

Command PatternWhy It's Safe
git checkout -b branchCreates new branch
git checkout --orphanCreates orphan branch
git restore --stagedOnly unstages, doesn't discard
git restore --help/--versionHelp/version output
git branch -dSafe delete with merge check
git clean -n / --dry-runPreview only
git push --force-with-leaseSafe force push
rm -rf /tmp/...Temp directories are ephemeral
rm -rf /var/tmp/...System temp directory
rm -rf $TMPDIR/...User's temp directory
rm -rf ./... (within cwd)Limited to current working directory
git restore / checkout -- / reset --hard / clean -f (in linked worktree)Relaxed only when CC_SAFETY_NET_WORKTREE=1 and cwd is a linked worktree

What Happens When Blocked

When a destructive command is detected, the plugin blocks the tool execution and provides a reason.

Example output:

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.

Testing the Hook

You can manually test the hook by attempting to run blocked commands in Claude Code:

# This should be blocked
git checkout -- README.md

# This should be allowed
git checkout -b test-branch

Breaking Change: Custom Rules Migration

[!WARNING] The custom rules system has moved from legacy inline config files to a rulebook-based layout. Legacy inline config files (.safety-net.json and ~/.cc-safety-net/config.json) are no longer loaded at runtime. If they contain rules, commands now fail closed (stay blocked) until you migrate.

Who Is Affected

  • Affected: users who previously defined custom rules in .safety-net.json (project scope) or ~/.cc-safety-net/config.json (user scope).
  • Not affected: users with no custom rules. All built-in destructive-command protections are unchanged and continue to work out of the box.

What Breaks

Legacy file stateNew behavior
Empty legacy fileSilently ignored — built-in rules only
Legacy file with rulesFail closed until migrated with rule migrate
Invalid legacy fileFail closed until fixed and migrated, or removed

"Fail closed" means commands stay blocked until the legacy rules are migrated to the new layout.

How to Migrate

# Convert legacy inline rules into the new rulebook layout
npx -y cc-safety-net rule migrate

# Optionally delete verified legacy files after migration
npx -y cc-safety-net rule migrate --cleanup

# Validate the migrated rules
npx -y cc-safety-net rule verify
npx -y cc-safety-net rule test

Before / After

Before — a single inline config with rules embedded:

.safety-net.json          # project rules (inline)
~/.cc-safety-net/config.json   # user rules (inline)

Afterrule migrate creates a rulebook-based layout automatically:

.cc-safety-net/rules/rule.json                    # project rulebook sources + overrides
.cc-safety-net/rules/project-rules/rulebook.json  # migrated project rules
~/.cc-safety-net/rules/rule.json                  # user rulebook sources + overrides
~/.cc-safety-net/rules/user-rules/rulebook.json   # migrated user rules

See Custom Rules for the full authoring guide and Error Handling for fail-closed details.

Custom Rules

Beyond the built-in protections, you can define your own blocking rules to enforce team conventions or project-specific safety policies.

[!TIP] The best way to create custom rules is to use the /cc-safety-net skill to create custom rules interactively with natural language.

Examples

/cc-safety-net read my package.json and suggest blocking rules
/cc-safety-net set up rules to block all terraform destroy commands
/cc-safety-net verify my rules and fix any errors

[!NOTE] If your agent does not support skills, prompt it with:

run npx -y cc-safety-net rule doc and help me set up custom rules

Create Rules Manually

Create a starter project rule config and rulebook:

npx -y cc-safety-net rule init

This creates .cc-safety-net/rules/rule.json:

{
  "version": 1,
  "rules": ["project-rules"],
  "overrides": {}
}

Rule definitions live in .cc-safety-net/rules/project-rules/rulebook.json:

{
  "rulebook_version": 1,
  "name": "project-rules",
  "version": "1.0.0",
  "description": "Project-specific CC Safety Net rules.",
  "author": "project",
  "allowed_commands": ["git"],
  "rules": [
    {
      "name": "block-git-add-all",
      "command": "git",
      "subcommand": "add",
      "block_args": ["-A", "--all", "."],
      "reason": "Use 'git add <specific-files>' instead of blanket add."
    }
  ],
  "tests": [
    {
      "command": "git add -A",
      "expect": "blocked",
      "rule": "block-git-add-all"
    },
    {
      "command": "git add README.md",
      "expect": "allowed"
    }
  ]
}

After editing rulebooks, run:

npx -y cc-safety-net rule sync
npx -y cc-safety-net rule verify
npx -y cc-safety-net rule test

Now git add -A, git add --all, and git add . will be blocked with your custom message.

Config File Location

Config files are loaded from two scopes and merged:

  • User scope: ~/.cc-safety-net/rules/rule.json (use rule init --global)
  • Project scope: .cc-safety-net/rules/rule.json in the current working directory

Local rulebook sources are bare names like project-rules. GitHub rulebook sources use owner/repo#ref/<rulebook-name> and point to .cc-safety-net/rules/<rulebook-name>/rulebook.json in that repository.

Legacy inline config files (.safety-net.json and ~/.cc-safety-net/config.json) are no longer loaded at runtime. Empty legacy files are ignored, but legacy files with rules and invalid legacy files fail closed until migrated or fixed. Convert existing legacy rules with npx -y cc-safety-net rule migrate; use npx -y cc-safety-net rule migrate --cleanup if you also want to delete verified legacy files after migration. See Breaking Change: Custom Rules Migration for the full upgrade guide.

Merging behavior:

  • Rulebooks from both scopes are combined
  • Duplicate active rulebook names are invalid
  • Project overrides win over user overrides for the same <rulebook-name>/<rule-name> key

This allows you to define personal defaults in user scope while letting projects disable or replace reasons for specific rules.

If no config file is found in either location, only built-in rules apply.

Config Schema

FieldTypeRequiredDescription
versionintegerYesSchema version (must be 1)
rulesarrayNoList of rulebook source strings (defaults to empty)
overridesobjectNoRule overrides keyed by <rulebook-name>/<rule-name>

Override values are either "off" to disable a rule or { "reason": "..." } to replace the rule reason.

Rulebook Schema

FieldTypeRequiredDescription
rulebook_versionintegerYesRulebook schema version (must be 1)
namestringYesRulebook name; must match the local directory name or GitHub source name
versionstringYesRulebook version
descriptionstringNoHuman-readable description
authorstringNoRulebook author
allowed_commandsarrayYesCommands this rulebook is allowed to define rules for
rulesarrayYesCustom blocking rules
testsarrayYesRulebook fixtures

Rule Schema

FieldTypeRequiredDescription
namestringYesUnique within the rulebook (letters, numbers, hyphens, underscores; max 64 chars)
commandstringYesBase command to match; must be listed in allowed_commands
subcommandstringNoSubcommand to match (e.g., add, install). If omitted, matches any.
block_argsarrayYesArguments that trigger the block (at least one required)
reasonstringYesMessage shown when blocked (max 256 chars)

Fixture Schema

FieldTypeRequiredDescription
commandstringYesShell command fixture
expectstringYesEither blocked or allowed
rulestringFor blocked fixturesRule expected to block the command

Every rule must have at least one blocked fixture. Add allowed fixtures for close-but-safe commands.

Matching Behavior

  • Commands are normalized to basename (/usr/bin/gitgit)
  • Subcommand is the first non-option argument after the command
  • Arguments are matched literally (no regex, no glob), with short option expansion
  • A command is blocked if any argument in block_args is present
  • Short options are expanded: -Ap matches -A (bundled flags are unbundled)
  • Long options use exact match: --all-files does NOT match --all
  • Custom rules only add restrictions—they cannot bypass built-in protections

Known Limitations

  • Short option expansion: -Cfoo is treated as -C -f -o -o, not -C foo. Blocking -f may false-positive on attached option values.

Rule Examples

Block global npm installs

.cc-safety-net/rules/rule.json:

{
  "version": 1,
  "rules": ["project-rules"],
  "overrides": {}
}

.cc-safety-net/rules/project-rules/rulebook.json:

{
  "rulebook_version": 1,
  "name": "project-rules",
  "version": "1.0.0",
  "allowed_commands": ["npm"],
  "rules": [
    {
      "name": "block-npm-global",
      "command": "npm",
      "subcommand": "install",
      "block_args": ["-g", "--global"],
      "reason": "Global npm installs can cause version conflicts. Use npx or local install."
    }
  ],
  "tests": [
    {
      "command": "npm install -g typescript",
      "expect": "blocked",
      "rule": "block-npm-global"
    },
    {
      "command": "npm install typescript",
      "expect": "allowed"
    }
  ]
}

Block dangerous docker commands

{
  "rulebook_version": 1,
  "name": "project-rules",
  "version": "1.0.0",
  "allowed_commands": ["docker"],
  "rules": [
    {
      "name": "block-docker-system-prune",
      "command": "docker",
      "subcommand": "system",
      "block_args": ["prune"],
      "reason": "docker system prune removes all unused data. Use targeted cleanup instead."
    }
  ],
  "tests": [
    {
      "command": "docker system prune",
      "expect": "blocked",
      "rule": "block-docker-system-prune"
    },
    {
      "command": "docker ps",
      "expect": "allowed"
    }
  ]
}

Multiple rules

{
  "rulebook_version": 1,
  "name": "project-rules",
  "version": "1.0.0",
  "allowed_commands": ["git", "npm"],
  "rules": [
    {
      "name": "block-git-add-all",
      "command": "git",
      "subcommand": "add",
      "block_args": ["-A", "--all", ".", "-u", "--update"],
      "reason": "Use 'git add <specific-files>' instead of blanket add."
    },
    {
      "name": "block-npm-global",
      "command": "npm",
      "subcommand": "install",
      "block_args": ["-g", "--global"],
      "reason": "Use npx or local install instead of global."
    }
  ],
  "tests": [
    {
      "command": "git add -A",
      "expect": "blocked",
      "rule": "block-git-add-all"
    },
    {
      "command": "npm install -g typescript",
      "expect": "blocked",
      "rule": "block-npm-global"
    }
  ]
}

Error Handling

Rulebook-backed custom rules fail closed when configured rulebooks cannot be loaded safely:

ScenarioBehavior
Config file not foundSilent — use built-in rules only
Invalid rule configFail closed until fixed
Empty legacy configSilent — use built-in rules only
Legacy config with rules and no migrated rule configFail closed until rule migrate creates the new rule config
Invalid legacy configFail closed until fixed or removed
Missing or stale lock/cacheFail closed until rule sync repairs it
Invalid local rulebookFail closed until the rulebook is fixed and synced
Invalid GitHub rulebookFail closed until the source is fixed or removed

[!IMPORTANT]
If you add or modify custom rules manually, always validate them with npx -y cc-safety-net rule verify and npx -y cc-safety-net rule test.

Block Output Format

When a custom rule blocks a command, the output includes the rule name:

BLOCKED by CC Safety Net

Reason: [block-git-add-all] Use 'git add <specific-files>' instead of blanket add.

Command: git add -A

Advanced Features

Mode and debug flags use CC_SAFETY_NET_* environment variables. Older SAFETY_NET_* names (without the CC_ prefix) still work for strict, paranoid, and worktree toggles.

Strict Mode

Malformed or missing hook input JSON always fails closed. By default, ambiguous shell command parsing is allowed through. Enable strict mode to fail closed when a shell command cannot be safely analyzed (e.g., unterminated quotes or malformed bash -c wrappers):

export CC_SAFETY_NET_STRICT=1

Paranoid Mode

Paranoid mode enables stricter safety checks that may be disruptive to normal workflows. You can enable it globally or via focused toggles:

# Enable all paranoid checks
export CC_SAFETY_NET_PARANOID=1

# Or enable specific paranoid checks
export CC_SAFETY_NET_PARANOID_RM=1
export CC_SAFETY_NET_PARANOID_INTERPRETERS=1

Paranoid behavior:

  • rm: blocks non-temp rm -rf even within the current working directory.
  • interpreters: blocks interpreter one-liners like python -c, node -e, ruby -e, and perl -e (these can hide destructive commands).

Worktree Mode

Linked git worktrees are designed as disposable, isolated workspaces — discarding changes inside one doesn't risk the main working tree. Worktree mode relaxes local-discard rules when (and only when) the command is proven to run inside a linked worktree:

export CC_SAFETY_NET_WORKTREE=1

When enabled, these commands are allowed inside a linked worktree:

  • 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 switch --discard-changes and git switch -f / --force
  • git reset --hard and git reset --merge
  • git clean -f (and combined short flags like -fd)

These remain blocked even in linked worktrees because they reach beyond the local working tree:

  • git push --force (affects remote)
  • git branch -D (affects shared refs)
  • git stash drop / git stash clear (stash is shared across worktrees)
  • git worktree remove --force (could delete another worktree)

Detection is fail-closed and mostly filesystem-based:

  • A linked worktree is identified by a .git file containing gitdir: whose resolved git directory contains a commondir file. Main worktrees and submodules don't satisfy this and are not relaxed.
  • The cwd walk uses realpath so symlinked paths resolve correctly.
  • git -C <path> (including chained -C and attached -Cpath) is honored; unresolved targets keep the command blocked.
  • Relaxation is disabled if cwd becomes unknown (e.g., after cd/pushd), if --git-dir / --work-tree is passed, or if GIT_DIR / GIT_WORK_TREE / GIT_COMMON_DIR is set in the environment.
  • Git may be invoked from a trusted system path to inspect effective config that could make submodule operations recursive.

Shell Wrapper Detection

The guard recursively analyzes commands wrapped in shells:

bash -c 'git reset --hard'    # Blocked
sh -lc 'rm -rf /'             # Blocked
bash -c 'git stash drop'      # Blocked

Interpreter One-Liner Detection

Detects destructive commands hidden in Python/Node/Ruby/Perl one-liners:

python -c 'import os; os.system("rm -rf /")'  # Blocked
python -c 'import os; os.system("git stash drop")'  # Blocked
python -c 'import os; os.system("dd if=/dev/zero of=/dev/sda")'  # Blocked
python -c 'import os; os.system("mkfs.ext4 /dev/sda1")'  # Blocked
python -c 'import os; os.system("shred -u secret.txt")'  # Blocked

Secret Redaction

Block messages automatically redact sensitive data (tokens, passwords, API keys) to prevent leaking secrets in logs.

Audit Logging

All blocked commands are logged to ~/.cc-safety-net/logs/<session_id>.jsonl for audit purposes:

{"ts": "2025-01-15T10:30:00Z", "command": "git reset --hard", "segment": "git reset --hard", "reason": "...", "cwd": "/path/to/project"}

Sensitive data in log entries is automatically redacted.

Development

See CONTRIBUTING.md for details on how to contribute to this project.

License

MIT

Keywords

claude-code

FAQs

Package last updated on 05 Jun 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts