Containment answers a different question from every other detector: not “does this look
like an attack?” but “was the agent ever authorized to do this?” Opt-in and
fail-closed — read the cost before enabling it in production.
Why detection alone has a ceiling
Nasr et al., The Attacker Moves Second (USENIX Security 2026), ran tuned, search-based attacks with detector-score feedback against twelve published defenses and bypassed all of them at over 90% attack success — including detectors architecturally similar to ours. Most had originally reported near-zero attack success on static benchmarks. The paper states plainly that stacking more detectors does not fix it. That result is not an argument against detection. It is an argument about where the answer comes from:
This is the core idea behind CaMeL and
FIDES: derive the policy from trusted input, then enforce
it regardless of what the untrusted channel says.
Before you enable it: the objective must be trusted
How it works
user_objective is parsed into a capability envelope — which of the four
capability axes the stated task
authorizes. Every tool call is then checked against it.
Containment is deterministic — no LLM. A judge that can be prompted is a judge an
injection can argue with, and the whole value here is that the policy is not negotiable.
The trade-off is that derivation is keyword-based and therefore imprecise, which is exactly
why it is opt-in and why an unrecognized objective grants nothing rather than everything.
It catches what dataflow analysis structurally cannot
Consider an agent told to summarize tickets that instead deletes a file. Nothing leaked — there is no tainted value and no sink — soFLOW001 correctly
reports nothing. Containment still blocks it:
The two are complementary: containment bounds what is reachable; taint analysis inspects
what happens inside those bounds. An objective that legitimately grants
send_email still
should not send your API key — that is FLOW001’s job.
Enabling it
public_sink and destructive.
Reading is comparatively safe, and containing it too would stop most legitimate agents dead.
Pass enforced_axes to widen or narrow that.
What this costs you
Be clear-eyed about this before switching it on:- An agent whose objective does not name its side effects will be stopped. “Handle my inbox” does not authorize sending. If your objectives are terse or auto-generated, expect false positives.
- Unrecognized objectives grant nothing. That is the correct direction for a containment control, and it is disruptive.
- An unlabeled tool is not contained — same limitation as FLOW001. A tool with no capability labels has no capability to check, so labeling remains the one step worth being thorough about.
- One authorized send authorizes other ordinary sends. Containment is axis-level. “Send
the report to finance” grants
public_sink, which also permitssend_emailto an attacker-chosen recipient — FLOW001 remains the control that inspects which value reaches that sink. The exception is below. - Derivation is keyword-based, not semantic. It reads verbs of transmission
(
send,publish,forward) and destruction (delete,cancel,transfer). Ambiguous nouns need a direction to count: “email the report to finance” authorizes a send; “delete all emails from newsletters” does not.
High-consequence capabilities must be named
Axis granularity alone turned out to be too coarse, and an adaptive attack against our own control found it: “Book me a table tonight” legitimately grantspublic_sink — a
reservation is an outbound action — and that grant then also authorized send_money, because
both tools carry the same axis. Money movement, for free, off an unrelated dinner booking.
So a tool whose name announces a high-consequence capability must have that capability named
in the objective too, whatever the axis says:
Covered tokens:
money, fund, payment, transfer, wire, withdraw, crypto,
wallet, password, credential, secret. The rule is inert for ordinary tools —
send_email carries none of these — so it adds no false positives on the common case. Only
tools that announce they move money or handle credentials have to be asked for by name.
Reading the finding
threat_type for a containment-only finding is unauthorized_capability.
Next steps
Agent Trace Analysis
Submit a run and label your tools
Threat Detection
What each detector catches