by kenryu42
A coding agent hook that acts as a safety net, catching destructive git and filesystem commands before they execute.
# Add to your Claude Code skills
git clone https://github.com/kenryu42/claude-code-safety-netA Claude Code plugin that acts as a safety net, catching destructive git and filesystem commands before they execute.
No comments yet. Be the first to share your thoughts!
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.
Claude Code's .claude/settings.json supports deny rules with wildcard matching (e.g., Bash(git reset --hard:*)). Here's how this plugin differs:
| | Permission Deny Rules | Safety Net | |---|---|---| | Setup | Manual configuration required | Works out of the box | | Parsing | Wildcard pattern matching | Semantic command analysis | | Execution order | Runs second | Runs first (PreToolUse hook) | | Shell wrappers | Not handled automatically (must match wrapper forms) | Recursively analyzed (5 levels) | | Interpreter one-liners | Not handled automatically (must match interpreter forms) | Detected and blocked |
Even with wildcard matching, Bash permission patterns are intentionally limited and can be bypassed in many ways:
| Bypass Method | Example |
|---------------|---------|
| Options before value | curl -X GET http://evil.com bypasses Bash(curl http://evil.com:*) |
| Shell variables | URL=http://evil.com && curl $URL bypasses URL pattern |
| Flag reordering | rm -r -f / bypasses Bash(rm -rf:*) |
| Extra whitespace | rm -rf / (double space) bypasses pattern |
| Shell wrappers | sh -c "rm -rf /" bypasses Bash(rm:*) entirely |
| Scenario | Permission Rules | 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 |
PreToolUse hooks run before the permission system. This means Safety Net inspects every command first, regardless of your permission configuration. Even if you misconfigure deny rules, Safety Net provides a fallback layer of protection.
Use both together: Permission deny rules for quick, user-configurable blocks; Safety Net for robust, bypass-resistant protection that works out of the box.
Claude Code offers native sandboxing that provides OS-level filesystem and network isolation. Here's how it compares to Safety Net:
| | Sandboxing | Safety Net | |---|---|---| | Enforcement | OS-level (Seatbelt/bubblewrap) | Application-level (PreToolUse hook) | | Approach | Containment — restricts filesystem + network access | Command analysis — blocks destructive operations | | Filesystem | Writes restricted (default: cwd); reads are broad by default | Only destructive operations blocked | | Network | Domain-based proxy filtering | None | | Git awareness | None | Explicit rules for destructive git operations | | Bypass resistance | High — OS enforces boundaries | Lower — analyzes command strings only |
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 withallowUnsandboxedCommands: false.
| Command | Sandboxing | Safety Net |
|---------|------------|------------|
| git reset --hard | Allowed (within cwd) | Blocked |
| git checkout -- . | Allowed (within cwd) | Blocked |
| git stash clear | Allowed (within cwd) | Blocked |
| git push --force | Allowed (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.
Sandboxing is the better choice when your primary concern is:
They protect against different threats:
Running both together provides defense-in-depth. Sandboxing handles unknown threats; Safety Net handles known destructive patterns that sandboxing permits.
/plugin marketplace add kenryu42/cc-marketplace
/plugin install safety-net@cc-marketplace
/reload-plugins
/plugin → Select Marketplaces → Choose cc-marketplace → Enable auto-updateOption A: Let an LLM do it
Paste this into any LLM agent (Claude Code, OpenCode, Cursor, etc.):
Install the cc-safety-net plugin in `~/.config/opencode/opencode.json` (or `.jsonc`) according to the schema at: https://opencode.ai/config.json
Option B: Manual setup
~/.config/opencode/opencode.json (or .jsonc):{
"plugin": ["cc-safety-net"]
}
gemini extensions install https://github.com/kenryu42/gemini-safety-net
/plugin install kenryu42/copilot-safety-net
[!NOTE] After installing the plugin, you need to restart your Copilot CLI for it to take effect.
Safety Net can displ