We don't say it's exploitable. We run the exploit.
Reachability tells you a path exists in the design. Attestral goes one step further and executes it: an isolated sandbox agent reads a planted canary and tries to exfiltrate it, a parent-side oracle measures whether it actually left, and an egress guard proves the run stayed contained. A proven exploit then compiles into a runtime deny.
attestral pentest ./my-project
One run, two measured facts.
The sandbox agent reads a planted canary and tries to exfiltrate it. The real outbound to the attacker host is stopped at the egress guard, so the run stays contained. The canary still reaches the instrumented sink the harness watches, so exfiltration is proven. Both are observed in the run, not asserted.
From "a path exists" to "the canary left, and here is the transcript."
Each tier is deterministic and offline, and each builds on the one before it. The first two describe the attack; the third runs it.
Reachable
Walk the attack path over the model's own edges. Every rung is a capability the design declares. Deterministic, no execution, committed to the evidence chain.
Predicted
An LLM drafts the injection text and the predicted tool-call sequence for the proven path, validated structurally against the model so it cannot wander off it. Labeled predicted, never executed.
Proven
Spawn an isolated sandbox agent, plant a canary, and let it try to exfiltrate. Two facts get measured, not narrated: did the canary reach the sink, and was the real outbound blocked.
Measured, not asserted.
The oracle lives in the parent process, so exfiltration is something the harness observes, not something the sandbox reports about itself. The attacker host is a real outbound that the egress guard blocks, so the exploit is demonstrated and contained in the same run.
Own stubs only. The harness runs Attestral's own stub agents with a planted canary. No live agent, no real secret, no real network. The induced tool sequence is the modeled one, so the run is deterministic; a live-target driver plugs into the same result schema and stays gated.
Pick how hard the jail is.
One flag, four backends behind one result schema. The default is a real OS process; the strongest removes the network entirely.
| Backend | Isolation | Exfil oracle | Containment |
|---|---|---|---|
| inprocess | same process | loopback sink | egress guard |
| subprocess | separate OS process (default) | loopback sink | egress guard |
| hardened | subprocess in a POSIX jail: new session, isolated cwd, cleared env, CPU / fd / process rlimits | loopback sink | egress guard |
| container | docker --network none | mounted volume | no network at all: real egress is structurally impossible |
attestral pentest ./my-project --isolation container
17 techniques, 7 classes, grounded in the benchmarks.
For each reachable path, --techniques synthesizes the concrete injection payloads a real attacker would try, canary-anchored and framework-mapped to AgentDojo, MCPTox, Invariant Labs, Trail of Bits, OWASP and MITRE ATLAS. --probe then measures whether a real model actually follows each one.
Payloads are sanitized test artifacts for your own agent: a benign canary marker, a placeholder attacker channel, no real secret and no destructive action. The two system-model-only classes, tool-name shadowing and A2A session smuggling, are the ones a single-file linter can never see.
Every payload composes with an evasion layer via --variants (base64, ROT13, hex, homoglyph, unicode tag-block, zero-width, HTML-comment, ANSI), so you can test which obfuscation slips past an input filter. And offense informs defense: the same taxonomy, inverted, is a detection rule (ATL-175) that catches a tool description hiding invisible or encoded instructions.
A proven exploit becomes a runtime deny.
This is the arc the rest of the tool is built around, and the part a rule-list scanner or a pure-LLM tool cannot assemble: the design review, the executed proof, and the enforced policy are one pipeline.
Model the system
Components, edges, trust boundaries. Find the lethal trifecta.
Run it in the sandbox
The canary leaving the instrumented sink is the ground truth.
Compile a deny
The egress server is denied until the path is broken.
Before the proof, the egress server is allowed. After the sandbox proves the canary leaves through it, the compiled default-deny policy denies that exact server, tagged with the proof. Static review, then sandbox-proven exploit, then runtime-enforced deny.
Run against the fixtures, not just a demo.
Pointed at the reference designs that ship with Attestral, the harness does not just flag reachable paths. It executes each one.
Every executed exploit was also contained. That is the property that makes this safe to run in CI: the proof reaches the instrumented sink, never the outside world. Gate a build with attestral pentest . --fail-on-exfil.
What a green run does, and does not, prove.
A reachable, executed exploit proves the declared design permits the flow to complete against the tool's own stubs. It does not prove a live LLM would follow the injection, that a guardrail or human approval was absent at runtime, or that the design is safe. A clean run over a weak design is still a weak design. The value is that the proof is executed and contained, and it becomes something the runtime policy enforces.
Prove your own agent's exploit in a sandbox.
pip install attestral