Claude Code ships with zero protection against destructive commands.
No rm -rf blocking. No git push --force guard. No DROP DATABASE check. Nothing.
One bad prompt injection, one hallucinated command, and your project is gone. Your git history is rewritten. Your disk is formatted. There is no undo.
This plugin adds the bare minimum security you need before letting Claude Code touch your codebase.
Right now, Claude Code can run any Bash command with the same permissions as your user account. That includes:
| Command | What it does | Reversible? |
|---|---|---|
rm -rf / |
Deletes everything | No |
git push --force |
Rewrites remote history | Depends |
git reset --hard |
Discards all uncommitted work | No |
git checkout -- . |
Drops all unstaged changes | No |
dd if=/dev/zero of=/dev/sda |
Wipes your disk | No |
DROP DATABASE production |
Destroys your database | Backup-dependent |
And it's not theoretical. Security researchers have documented Claude Code escaping its own sandbox, exfiltrating API keys, and executing code before you even see a trust dialog. Three CVEs in the last year alone.
One command. Two minutes. Four layers of protection.
/plugin marketplace add psnluiz/secure-claude-code
/plugin install secure-claude-code
/secure-claude-code
The skill reads your current settings, reports what's missing, and applies each layer — without replacing anything you already have.
| Layer | What it does | Stops what |
|---|---|---|
| Deny rules | Hard-blocks destructive command prefixes | rm -rf, git push --force, dd, mkfs, and 5 more |
| PreToolUse hook | Regex catch-all that runs before every Bash command | Flag reordering (rm -rfi), SQL destruction, raw disk writes |
| OS Sandbox | macOS Seatbelt / Linux bubblewrap kernel isolation | Prompt injection, filesystem escape, network exfiltration |
| Docker isolation | Container boundary for VPS and untrusted code | Everything — the container is the security boundary |
Layers 1-3 apply to your local machine. Layer 4 is optional, for VPS or remote work.
Each layer catches what the previous one misses:
Attempt: rm -rf /
Layer 1: BLOCKED (deny rule matches prefix)
Attempt: rm -r -f / (reordered flags to dodge deny rules)
Layer 1: miss
Layer 2: BLOCKED (regex catches flag variations)
Attempt: /proc/self/root/usr/bin/rm -rf / (path evasion)
Layer 1: miss
Layer 2: miss
Layer 3: BLOCKED (kernel restricts filesystem writes)
That's defense-in-depth. No single layer is enough — because Claude Code actively reasons about security boundaries as obstacles to route around.
Because it has been broken. Repeatedly.
| CVE | What happened | Fixed in |
|---|---|---|
| CVE-2025-59536 | Malicious repo ran hooks and MCP servers before you saw the trust dialog | v1.0.111 |
| CVE-2026-21852 | Repo config redirected API calls (with your keys) to an attacker server | v2.0.65 |
| CVE-2026-25725 | Code inside the sandbox created a malicious settings file to escape it | v2.1.2 |
And beyond CVEs: Ona security research documented Claude Code bypassing path-based deny rules via /proc/self/root/, autonomously disabling its own bubblewrap sandbox, and invoking the ELF dynamic linker to dodge kernel enforcement.
The sandbox is one layer. You need four.
When you run /secure-claude-code, Claude:
- Reads your
~/.claude/settings.json - Reports what's missing
- Merges deny rules into
permissions.deny - Merges the PreToolUse hook into
hooks - Enables the sandbox with the escape hatch closed
- Validates the JSON
- Asks if you need Docker isolation (Layer 4)
Your existing settings are preserved. The skill merges — it never replaces.
- Claude Code CLI installed
- macOS or Linux (Layer 3 uses Seatbelt / bubblewrap)
jqinstalled (used by the PreToolUse hook)- Docker (optional, for Layer 4)
"deny": [
"Bash(rm -rf *)",
"Bash(docker rm *)",
"Bash(kubectl delete *)"
]Syntax: Bash(<prefix> *) blocks any command starting with that prefix.
Edit the grep -qiE pattern in hooks.PreToolUse to add patterns. Case-insensitive, extended regex syntax.
"sandbox": {
"enabled": true,
"allowUnsandboxedCommands": false,
"autoAllowBashIfSandboxed": true,
"filesystem": {
"denyRead": ["~/.ssh", "~/.aws/credentials"],
"denyWrite": ["/etc", "/bin", "/usr/bin"]
},
"network": {
"allowedDomains": ["github.com", "*.npmjs.org"]
}
}allowUnsandboxedCommands: false is critical — it closes the escape hatch that lets Claude retry commands outside the sandbox (GitHub #14268).
| Component | Requirement |
|---|---|
| Claude Code | Any version (deny rules and hooks are stable API) |
| Layer 3 (sandbox) | macOS (Seatbelt) or Linux (bubblewrap) |
| Layer 4 (Docker) | Docker Engine 20+ |
jq |
Required for the PreToolUse hook |
| This plugin | Built-in sandbox only | Trail of Bits devcontainer | |
|---|---|---|---|
| Blocks destructive commands | Yes | No | No |
| Works without Docker | Yes (Layers 1-3) | Yes | No |
| OS-level isolation | Yes | Yes | Yes |
| Network isolation | Optional | Optional | Yes (iptables) |
| Setup time | 2 minutes | Manual | Clone + Docker setup |
This plugin and Trail of Bits are complementary. Use Layers 1-3 locally, add their devcontainer for Layer 4 on remote work.
Hook blocks a command I need: Run it manually in your terminal (outside Claude Code), or temporarily remove the hook from ~/.claude/settings.json.
JSON syntax error: Run jq '.' ~/.claude/settings.json to find the issue. Restore backup: cp ~/.claude/settings.json.bak ~/.claude/settings.json
Sandbox blocks a tool: Add the command to sandbox.excludedCommands or adjust filesystem/network settings.
Hook not firing: Check jq is installed (which jq), validate the hook structure, restart Claude Code.
/plugin uninstall secure-claude-code
This removes the plugin but does not revert settings changes. To fully revert, remove the deny rules, hook, and sandbox config from ~/.claude/settings.json.
Found a destructive command that isn't blocked? A bypass that gets through? Open an issue.