# security-hooks Defense-in-depth security hooks for AI coding agents. Works with **Claude Code**, **Gemini CLI**, and **Codex**. A single daemon evaluates every tool call against configurable rules — blocking destructive commands, catching data exfiltration, and flagging suspicious behavior before it reaches your system. ## How it works ``` AI Agent ──► Rust Shim ──► Unix Socket ──► Elixir Daemon ──► Verdict (<1ms) (<1ms) (rule engine) allow/deny/ask ``` 1. The AI tool calls a hook before each tool use (bash command, file edit, MCP call) 2. A tiny Rust binary forwards the payload to a long-running Elixir daemon 3. The daemon evaluates rules using **two layers**: - **Regex** — fast pattern matching for obvious threats (fork bombs, miners) - **AST** — structural analysis via tree-sitter-bash that catches evasion (`rm -rf $(echo /)`, piped exfiltration, obfuscated commands) 4. Returns `allow`, `deny` (with a nudge message), or `ask` (falls through to human approval) The system is **fail-closed** — if the daemon is unreachable, the tool call is blocked. ## Threat coverage - **Prompt injection** — malicious content in READMEs, web pages, or MCP responses can't trick the agent into running blocked commands - **Destructive operations** — `rm -rf`, force push, `sudo`, cloud resource deletion, and more - **Data exfiltration** — detects secrets being piped to `curl`/`nc`, reads of `~/.ssh` or `~/.aws`, env var leaks - **Supply chain attacks** — flags dependency mutations, unknown executables, lockfile edits - **MCP injection** — validates MCP server identity, scans parameters for shell injection via AST ## Rule DSL Rules live in `.rules` files with a custom syntax designed for regex without escaping pain: ``` # Regex — pattern is literal to end of line, no quoting needed block "fork-bomb" match :\(\)\s*\{.*\|.*&\s*\}\s*; nudge "Fork bomb detected" # AST — structural matching that catches evasion block "destructive-rm" match command("rm") with_flags("-r", "-rf", "-fr") nudge "Use trash-cli or move to a temp directory" block "pipe-to-exfil" match pipeline_to("curl", "wget", "nc") nudge "Don't pipe output to network commands" # Config-referenced allowlist suspicious "unknown-executable" match_base_command_not_in allowed_executables nudge "Unknown command '{base_command}'. Add it to config.toml" ``` The rule loader auto-detects regex vs AST based on whether the match starts with a function like `command(`. ## Two tiers - **block** — hard deny. The agent sees the nudge and self-corrects. - **suspicious** — falls through to the human permission prompt with context. ## Configuration ```toml # config.toml — defaults ship with the project [executables] allowed = ["git", "mix", "cargo", "go", "node", "npm", "python", "rg", "fd", ...] [secrets] env_vars = ["AWS_SECRET_ACCESS_KEY", "GITHUB_TOKEN", "DATABASE_URL", ...] [paths] sensitive = ["~/.ssh", "~/.aws/credentials", "~/.config/gcloud", ...] ``` Override with `config.local.toml` (gitignored): ```toml [executables] append = ["my-custom-tool", "deno"] exclude = ["curl"] [rules] disabled = ["force-push"] ``` ## Architecture - **Rust shim** — ~1MB static binary, <1ms startup, forwards payloads via Unix socket - **Elixir daemon** — distributed as a [Burrito](https://github.com/burrito-elixir/burrito) binary (no Erlang/Elixir install needed) - **Adapter layer** — normalizes payloads across Claude Code, Gemini CLI, and Codex - **tree-sitter-bash** — Rust NIF for robust AST parsing of shell commands - **Hot-reload** — edit rules or config, changes apply on the next tool call - **systemd/launchd** — socket activation for zero cold-start latency, automatic crash recovery ## Platforms macOS (aarch64, x86_64) · Linux (x86_64, aarch64) · WSL ## Status Design phase. See [`docs/superpowers/specs/2026-03-26-security-hooks-design.md`](docs/superpowers/specs/2026-03-26-security-hooks-design.md) for the full spec. ## License TBD