Red-team · executed, contained

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
What actually happens

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.

isolated sandbox · its own OS process untrusted input stub agent reads the secret secret store canary egress guard blocked attacker host (real network) instrumented sink (oracle) real outbound canary → egress channel exfiltrated
canary token egress guard blocks the real outbound instrumented sink receives the canary
Three tiers, one schema

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.

Tier 0 · symbolic

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.

Tier 1 · generative

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.

Tier 2 · 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.

The executed harness

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.

$ attestral pentest ./my-project Executed pentest (tier 2 - 1 path(s), isolated sandbox, planted canary, no live target) internal path canary ATTESTRAL-CANARY-82abe9a5d4 (isolated subprocess) 1. entry: web ingests content carrying an injected instruction (canary bait) observed: instruction accepted by the stub agent 2. pivot: ops reads the planted secret (stub filesystem: ~/.ssh/id_rsa) observed: read planted canary ATTESTRAL-CANARY-82abe9a5d4 3. impact: web POST canary to the attacker host (real outbound) observed: blocked by the sandbox egress guard (contained) 4. impact: web carry the secret out via the modeled egress channel observed: sent to the instrumented sink EXFILTRATED: the canary reached the sink CONTAINED: the real outbound was blocked by the guard

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.

Isolation, strongest last

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.

BackendIsolationExfil oracleContainment
inprocesssame processloopback sinkegress guard
subprocessseparate OS process (default)loopback sinkegress guard
hardenedsubprocess in a POSIX jail: new session, isolated cwd, cleared env, CPU / fd / process rlimitsloopback sinkegress guard
containerdocker --network nonemounted volumeno network at all: real egress is structurally impossible
attestral pentest ./my-project --isolation container
The attack-technique library

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.

Direct override3
ATK-01Instruction override ATK-11Refusal suppression ATK-13Authority frame
Indirect / second-order3
ATK-02HTML-comment ATK-03Tool-result poisoning ATK-14Markdown-image exfil
Obfuscation5
ATK-04Base64 ATK-05Tag-block smuggling ATK-06Homoglyph ATK-07Zero-width split ATK-12Line-jumping / ANSI
Tool poisoning3
ATK-08Description poisoning ATK-09Tool-name shadowing ATK-15Attractive metadata
Multi-turn1
ATK-10Crescendo escalation
Memory & multi-agent2
ATK-16Memory poisoning ATK-17A2A session smuggling

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.

Close the loop

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.

Review

Model the system

Components, edges, trust boundaries. Find the lethal trifecta.

Prove

Run it in the sandbox

The canary leaving the instrumented sink is the ground truth.

Enforce

Compile a deny

The egress server is denied until the path is broken.

$ attestral compile ./my-project --close-loop close-loop: 1 path(s) exfiltrated a canary in the sandbox; denying 1 egress server(s) on the proven path(s). [ALLOW] ops before the proof: the egress server was permitted [DENY ] web (denied by attested design review: ATL-RT-EXFIL)

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.

On real designs

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.

14
reference designs with a reachable attack path
14
exfiltrated a canary in the sandbox
14
stayed contained: the real outbound was blocked every time

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.

The honest boundary

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.

Run it

Prove your own agent's exploit in a sandbox.

pip install attestral