Delegation chains & deny-capable tool authorization (confused-deputy defense)#5
Merged
Conversation
A framework-level defense against the multi-agent confused deputy: an agent tricked into using legitimate authority for a request it shouldn't have. Implements stages 1–2 of docs/proposals/delegation-and-tool-authz.md. - DelegationContext / Principal: the originating user + the chain of acting agents, seeded via RunOptions.delegation. - Propagation: the chain flows into every tool via ToolRunContext.delegation and extends by one hop through each asTool sub-agent (extendChain). - authorizeToolCall hook: deny-capable, sees the full chain, runs at the tool-call seam before the tool executes. `false` denies one call (the model gets an error result and continues); throwing AuthorizationError aborts the run. Config + per-call hooks AND-merge. So a sub-agent can be barred from a resource regardless of a token it inherited through the context — authorization is against the identity chain, not a call path the agent loop picks at runtime. Fully opt-in, backward compatible. New exports: DelegationContext, Principal, ToolCallRequest, extendChain, AuthorizationError. 12 new tests (74 runtime total), incl. the confused-deputy composition scenario. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Jun 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A framework-level defense against the multi-agent confused deputy — an agent with legitimate authority tricked into using it for a request it shouldn't have (the failure mode in the Kagenti talk: a sub-agent reading patient records because a token rode along in the context).
Implements stages 1–2 of the design doc added here (
docs/proposals/delegation-and-tool-authz.md). It's the framework half of the story: TOAD produces and propagates the delegation chain and offers a deny point at the tool boundary. Enforcement/signing/mTLS at the infra tier stays a platform's job (Kagenti/Istio) — complementary, not competing.How — "secure the identity, not the path"
DelegationContext/Principal— the originating user (subject) plus the ordered chain of acting agents. Seeded once viaRunOptions.delegation.ToolRunContext.delegation, and extends by one hop through eachasToolsub-agent (extendChain), so a sub-agent's own tool calls authorize against the full chain.authorizeToolCallhook — deny-capable, sees{ tool, input, delegation, agent }, runs at the tool-call seam before the tool executes. Returnfalseto deny just that call (the model gets an error result and continues); throwAuthorizationErrorto abort the run. Config + per-call hooks AND-merge (both must allow).The point: authorization is decided against the identity chain, which travels with the request — not a call path the agent loop picks at runtime and which RBAC-on-topology can't express for agents.
Why it matters (the headline test)
delegation.test.tsincludes the confused-deputy scenario end-to-end:billingmay readpatient_records; it delegates to averifiersub-agent that tries the same tool. Because the chain at the sub-agent is[billing, verifier]and the policy requires every actor to be permitted, the read is denied — even thoughverifierwas reached through a legitimate caller. The orchestrator calling the tool directly ([billing]) is still allowed.Surface (all additive, all opt-in)
New exports:
DelegationContext,Principal,ToolCallRequest,extendChain,AuthorizationError. An agent that sets neitherdelegationnorauthorizeToolCallbehaves exactly as before.Verified
asToolchain extension, allow/deny/throw, chain-wide policy across composition, AND-merge, and backward-compat (no chain ⇒ctx.delegationundefined, tool runs).Not in this PR (stages 3–4, proposed in the doc)
serveMcpboundary header (Toad-Delegation) for gateway enforcement; optional JWS signing; a declarative.agentallow:block compiled bytoac.🤖 Generated with Claude Code