A survey of coding-agent security guards
A survey of Claude Code guardrails organized by what each tool can observe: a command, an audit trail, a sandbox boundary, or the provenance of data across a session.
1. Introduction and the question
When a developer lets Claude Code work on a real repository, the agent enters a setting in which ordinary development actions already have security consequences. It can read files, run commands, edit code, and make network calls while the shell may hold credentials, git remotes, package tokens, and a working tree it can change. The agent may be fixing a build, rotating a key, or testing a migration, but the same capabilities that make those tasks useful also create paths for disclosure, mutation, and execution.
The practical question is what should sit between the agent and the machine. The candidate mechanisms differ in how much of the agent’s activity they can observe, and therefore in how discerning a decision they can make. The narrowest observes only the single command about to run and judges it by how it looks. An audit layer observes the whole sequence of actions and preserves it as evidence, though only after each action has already run. The most comprehensive observes the provenance of data across the entire session, tracing where the values in the current action came from and which earlier, possibly sensitive, steps they depended on. A single guard may combine several of these vantage points, but the widest one it can observe sets a ceiling on the decisions it can make, since no mechanism can act on information it never sees.
Containment sits on a different axis altogether. A sandbox reasons about none of this, yet by confining the process it limits the damage any command can do, whatever a policy does or does not understand. It is complementary to the observation-based mechanisms rather than a point on the same scale, and the two can be combined.
In what follows, the central question is what each tool can actually see before it says allow, ask, deny, or record.
2. Vocabulary
A PreToolUse hook is Claude Code’s interception point before a tool call
runs. It receives the pending action and can allow it, ask the user, or deny it
before the shell command, file edit, or other tool call reaches the machine.
This placement distinguishes prevention from evidence, because a decision made
after execution can explain what happened but cannot stop the immediate effect.
We use write-then-execute for a sequence in which an agent writes malicious
code to an allowed file and later invokes it through an allowed runner, such as
npm test or python script.py. Because the danger need not be visible in the
runner command, this sequence remains a limitation of command-layer guards,
including sasy-guard. Provenance can catch exfiltration when outbound bytes
depend on a sensitive source, but it does not prove that a newly written script
is harmless.
Provenance means origin and lineage: where data came from, and which later
actions depended on it. Taint is the marker that says a value depends on a
sensitive source. If a command reads .env, transforms the contents, and sends
the result outward later, taint is the reason a policy can still remember the
origin. Egress is data leaving the machine or sandbox; fail-closed means calls
are denied when the enforcement component is unavailable; and an allowlist is a
list of permitted targets or actions.
Datalog is a rule language for deriving facts from other facts, and it matters here because policy decisions often depend on relationships among events rather than on a single string. A reference monitor is the enforcement component that mediates access, so the agent does not decide whether its own action is allowed. With those terms in place, the tools separate into permission guards that decide in the hook path, audit receipts that record after execution, and OS sandboxes that accept coarser control in exchange for a containment boundary.
3. The survey
We examine the tools in an order that exposes the design space: nah, rampart, cupcake, railguard, claude-hook-advisor, prismor, punkgo-jack, and the sandbox pair of sandclaude and claude-container. For each tool, we ask what it is, what mechanism it uses, what it does well, and where that mechanism stops. This is not a single ranking, because a pre-execution policy engine, a post-execution audit log, and a Docker boundary answer different questions.
The axes are therefore observational as much as functional. A tool may know a command deeply while knowing nothing about prior values, or it may preserve evidence without preventing the action, or it may reduce blast radius without understanding semantic data flow. The survey keeps those distinctions visible so that each tool is evaluated against the kind of thing it can actually see.
nah
nah is a lightweight Python guard distributed through PyPI. The project
recommends sandboxing agents and provides a guard for cases in which they are
not sandboxed. A Bash parser maps a single command into 43 action types, then
checks a fixed JSON policy table, with local context such as paths, sensitive
locations, and curl hosts refining the result.
The mechanism gives nah more command-local shell depth than most tools here,
but it also defines the boundary: nah is stateless and per-command, reading the
transcript for logging rather than for policy decisions, so it can catch
cat .env piped to curl inside one pipeline but not a read and egress split
across tool calls. nah has removed its taint.py and provenance.py, so its
current design moves away from persistent data-origin tracking.
Compared with sasy-guard, nah has a smaller installation footprint, PyPI packaging, multi-runtime reach across Claude Code, Codex, and terminal workflows, and deeper single-command parsing. It is a low-friction guard when the risk is visible in one command.
rampart
rampart is a Go policy engine distributed as a single binary. It carries more
operations machinery than any other tool surveyed, covering Claude Code and
OpenClaw hooks, then extending to Cline, Codex, wrapped shell commands, an MCP
proxy for Model Context Protocol traffic, and LD_PRELOAD syscall interception,
a Unix technique for watching low-level calls.
The operations surface includes terminal and web dashboards, security-tool
exports through syslog and Common Event Format logs, webhook alerts, a policy
REPL, a preflight API for checking before execution, a mapping to the OWASP
Agentic-2026 security checklist, inline policy tests, and starter templates.
Its policy model is a deterministic PreToolUse guard with YAML
match -> when -> action rules; deny wins through priorities, and conditions
include command_matches, path_matches, domain_matches,
response_matches, and call_count.
rampart stops short of taint and data flow. Its cross-call state is limited to
sliding-window call counters, per-session approvals, and one-response
secret-regex scanning. The author named bypassing .env files through side
channels as a threat, but rampart answers with per-command obfuscation
detection rather than provenance. It is therefore strong where a team needs an
operational policy system for local events, not a general source-to-sink graph.
cupcake
cupcake is a Rust policy-enforcement layer distributed through npm, Nix, and binaries. It is the only rival in this set with a compiled policy language. More precisely, it compiles Rego, a policy language, to Wasm, portable WebAssembly bytecode, and evaluates it through wasmtime, a WebAssembly runtime.
That mechanism matters because teams author policies in a real language and run them in a deterministic core instead of just toggling regexes or editing YAML tables. cupcake also provides SLSA-3 supply-chain build integrity, support for Claude Code, Cursor, Factory, and OpenCode, plus TypeScript and Python bindings.
cupcake evaluates one hook event at a time, which leaves memory as the main
gap. It does not read the transcript, reconstruct a session graph, or track
taint or lineage, so a later egress decision cannot be tied back to an earlier
.env read. Its product surface includes five decision types, including
Modify, context injection, auto-linting after edits, and an optional LLM
Watchdog that is disabled by default. The Watchdog is separate from the
deterministic core.
railguard
railguard is a compact Rust guard distributed through crates.io, with roughly 10.5k lines of code. Its main design choice is pairing ordered regex rules with OS-kernel sandboxing. The decision path checks allowlist regexes, blocklist regexes, approve regexes, and then falls back to default allow, while a 29-rule heuristic threat classifier sits beside that path.
The sandbox layer uses the kernel’s own confinement tools: macOS sandbox
profiles (sandbox-exec, SBPL) and Linux sandboxing (bwrap, Landlock). The
provenance terminology requires care, however, because railguard’s
provenance.rs signs memory .md files for integrity and tamper detection
rather than semantic data lineage; it does not tell whether an outbound action
depends on a prior sensitive read.
railguard has no policy language and no cross-call data-flow tracking. Its state is a shallow keyword-overlap retry detector in a three-call window plus per-session block history. Its operational extras include file snapshots, rollback, a ratatui terminal dashboard and replay view, and multi-agent file-locking.
claude-hook-advisor
claude-hook-advisor is a
Claude Code productivity advisor, not a security-enforcement product. It is a
Rust tool distributed through crates.io. Its relevant behavior is
deny-and-rewrite guidance: if Claude reaches for a disfavored CLI tool, the hook
can deny the action and steer it to the preferred tool, such as npm to bun.
claude-hook-advisor checks file edits with about 27 hardcoded literal substring
patterns that can only be toggled. Bash commands are checked only against
tool-preference mappings, so cat .env piped to curl passes untouched. There
is no parser, AST, policy language, provenance, or tamper resistance. SQLite
history and the already-warned file are analytics and deduplication state, not
security decision state.
prismor
prismor is a broad Python policy engine for coding agents. It ships hooks for Claude Code, Cursor, Windsurf, OpenClaw, Hermes, Codex, and GitHub Copilot CLI, plus adapters for OpenAI Agents SDK, CrewAI, LangChain/LangGraph, browser-use, Vercel AI SDK, and an HTTP eval-server.
prismor has 64 YAML detection rules with observe or enforce modes,
non-overridable core categories, allowlists, project overlays, and optional
signed remote policy overlays, meaning centrally signed rules layered on top of
local policy. Its secret cloaking substitutes @@SECRET:name@@ placeholders at
Bash execution time, scrubs Bash output, can deny raw-secret reads, and can scrub
MCP responses. It also scores packages with registry metadata, install scripts,
OSV lookup, typosquat checks, and hardcoded indicators for known malicious
packages.
prismor complicates the simple two-axis story because it has some session memory. It stores JSONL events, meaning one JSON event per line, plus SQLite sessions and findings. It can persist a prompt-injection taint flag and seen domains, then escalate later network events. That is real cross-call state, but it is not value-level source-to-sink lineage from an earlier read or tool output into a later outbound argument. Relative to sasy-guard, the hard stops are policy and provenance: prismor compiles regex alternations and evaluates YAML rules at runtime, but it does not have an authored policy language compiled ahead of enforcement; its default posture is observe-heavy, semantic prompt-injection detection is opt-in, and local hooks and YAML remain editable unless an enterprise signed remote policy layer is in use.
punkgo-jack
punkgo-jack is an orthogonal audit
tool written in Rust, not a prevention layer. It borrows the machinery of
certificate transparency: an append-only Merkle log (RFC 6962), signed
checkpoints (Ed25519), trusted timestamp anchoring (RFC 3161), inclusion and
consistency proofs, and Go sumdb/tlog cross-language verification.
Those mechanisms can prove what happened after the fact, but punkgo-jack
cannot stop execution. It registers PostToolUse, PostToolUseFailure,
SessionStart, and SessionEnd, but no PreToolUse hook, so it cannot allow,
ask, deny, or stop a leak before the tool call runs. Signed decision receipts
could extend sasy-guard by making every allow, ask, and deny externally
verifiable.
the sandbox pair
sandclaude and claude-container are OS containment tools rather than semantic policy engines. They answer a real criticism of hook-only systems, because a kernel boundary can reduce blast radius when an agent runs arbitrary processes.
sandclaude is a Bash script and Dockerfile that runs Claude
with --dangerously-skip-permissions inside an Ubuntu Docker container. That
gives a real host boundary outside the mounted workspace. The leaks are also
explicit: the workspace is mounted read-write, network egress is open, live
Claude OAuth is present, the host gh token and a Jira token are injected,
passwordless sudo is available, and the image build is heavyweight.
claude-container adds a more distinctive mechanism: a Docker-socket proxy. It rejects privileged containers, dangerous capabilities, host PID, host networking, and bind mounts outside the current working directory, while supporting Claude, Codex, and Gemini. Inside claude-container, full egress remains available; mounted AWS credentials, GitHub config, and git credentials are readable; and there is no per-action allow, ask, deny, compiled policy language, data-flow tracking, or configured exfiltration defense.
Rather than replacing a policy guard, these containment layers compose with one: running the policy brain inside the sandbox lets the OS boundary limit blast radius while the policy layer reasons about what data is leaving.
4. The pattern
Most tools intercept the same hook-shaped moment and judge a local event. punkgo-jack records after execution, while sandboxes move the boundary to the operating system. These are all useful layers, but they observe different things. Only cupcake and sasy-guard have compiled policy languages: cupcake uses Rego to Wasm, while sasy-guard uses Souffle Datalog and evaluates policies over a reconstructed session graph. prismor has regex compilation inside its runtime, but the authored policy surface is YAML evaluated by the engine. We introduced sasy-guard in an earlier post, focused on the hook and graph mechanism.
Only sasy-guard has value-level whole-session provenance among these tools: nah deleted its taint and provenance files; rampart keeps counters, approvals, and one-response secret scans; railguard uses its provenance file for integrity signing rather than data lineage; cupcake evaluates each hook event independently, so no earlier read can inform a later decision; and prismor persists narrow session taint for prompt-injection findings and later network escalation, but not a general data-flow graph. Our analysis therefore treats sandbox composition, allowlists, and data-flow reasoning as distinct controls rather than evidence that a hook forms a complete boundary. The limitation stays real: write-then-execute remains a gap for command-layer guards, and sasy-guard’s taint slice is turn-scoped.
The chart compares what each tool can decide before execution, while sandboxes and audit tools address adjacent layers rather than the same pre-execution decision problem.
5. sasy-guard
sasy-guard reconstructs the session as a message-dependency graph and evaluates compiled Souffle Datalog policies over that graph. In plain language, the guard asks where the data in the current action came from across the session before it lets the action run.
The core example is an outbound curl whose bytes trace back to a .env read.
The data may move through a subshell, base64, or a subagent. If the dependency
graph still reaches the sensitive source, the policy can deny the egress.
sasy-guard’s baseline strengths are deterministic enforcement with no LLM in
the path, roughly 13 guard groups, policy pinned per session, a locked engine
baked and bound by hash, and fail-closed behavior when enforcement is
unavailable.
Value-level whole-session provenance supplies the useful composition: a denylist can catch a known-bad command, and a policy language can express richer rules, while provenance lets those rules ask whether this outbound action depends on data it should not carry. That is the specific niche sasy-guard occupies; it does not replace sandboxes, audit receipts, or command-level heuristics.
6. What the rivals do better
nah has the advantage of a small installation footprint, PyPI packaging, multi-runtime reach, and a deep single-command shell parser when a team needs low-friction command checks. rampart has single-binary packaging, Homebrew installation, dashboards, security-event (SIEM) exports, webhook alerts, OWASP mapping, syscall interception, and starter templates, which give it the most extensive operations layer among the tools in this survey.
cupcake has Rego-to-Wasm policy compilation, SLSA-3 builds, npm, Nix, binary
distribution, multiple harnesses, TypeScript and Python bindings, Modify
decisions, and workflow automation. prismor has broader coding-agent and
framework coverage, secret cloaking, supply-chain scoring, SIEM-shaped exports,
signed remote policy overlays, and narrow prompt-injection taint across a
session. railguard and the sandbox pair provide kernel-backed containment,
which a hook cannot replace. punkgo-jack provides externally verifiable audit
evidence through Merkle logs, signed checkpoints, and timestamp anchoring.
7. The comparison table
The table summarizes the field. The two middle columns capture the axes that separate the tools most sharply, while tamper resistance describes how hard it is for the agent to edit or switch off the guard’s own rules. prismor’s “Narrow” means a persisted prompt-injection taint flag, not value-level lineage.
| Tool | Category | Policy model | Compiled policy | Session provenance | Tamper resistance | Strongest fit |
|---|---|---|---|---|---|---|
| sasy-guard | Permission guard | Souffle Datalog | Yes | Yes | locked | Provenance-aware policy guard |
| nah | Permission guard | JSON table plus YAML knobs | No | No | rule-based | Low-friction single-command checks |
| rampart | Policy engine / firewall | YAML glob, substring, regex | No | No | plaintext | Packaged operations story |
| cupcake | Policy-enforcement layer | Rego to Wasm | Yes | No | plaintext | Closest policy-language rival |
| railguard | Guard with OS sandbox | Ordered regex rules | No | No | rule-based | Regex plus kernel containment |
| claude-hook-advisor | Advisor / lint | Tool mappings and substrings | No | No | plaintext | Team workflow nudges |
| prismor | Policy engine | YAML plus regex rules | No | Narrow | rule-based | Broad hook and secret guardrails |
| punkgo-jack | Audit receipts | None | No | No | n/a | Proof after execution |
| sandclaude | OS sandbox | None | No | No | n/a | Simple container boundary |
| claude-container | OS sandbox | None | No | No | n/a | Nested-container guardrails |
8. Choosing a tool
The practical takeaway is that the right tool depends on the object the team needs to control. nah suits teams that want low-friction single-command checks, while rampart fits organizations that require packaging and enterprise operations. cupcake serves teams for which a compiled Rego-to-Wasm policy engine across harnesses matters most, and prismor addresses the case where broad agent and framework coverage, secret cloaking, and supply-chain guardrails are the immediate need. punkgo-jack answers the requirement of proof after the fact, and the sandboxes come first when the job is to limit blast radius.
sasy-guard applies when the risk is data moving across normal-looking steps and the policy needs to ask where the outbound action’s data came from. A layered posture combines a sandbox boundary for containment, a provenance-aware policy guard for semantic decisions, and audit receipts as the evidence layer.
References
- nah — Lightweight per-command guard.
- rampart — Go firewall with hooks, dashboards, exports, and alerts.
- cupcake — Rego-to-Wasm policy engine from EQTY Lab.
- railguard — Rust regex guard paired with OS sandboxing.
- claude-hook-advisor — Claude Code workflow advisor with lightweight edit linting.
- prismor — Broad Python policy engine with secret cloaking and narrow session taint.
- punkgo-jack — PostToolUse audit receipts with cryptographic verification.
- sandclaude — Docker wrapper that runs Claude with permission checks disabled.
- claude-container — Container runner with a Docker-socket proxy for nested containers.
- sasy-guard docs (setup) — Setup docs for using sasy-guard with Claude Code.
- sasy-guard on PyPI — Python package distribution page.
- Why sasy-guard (DIY-hooks comparison) — DIY-hooks comparison and rationale.
- Sasy Guard repository — The Sasy Guard suite and Claude Code plugin marketplace.