Agentic architecture
Verified by ROOTVIEL11 minConfused Deputy
An agent holds privileges and credentials of its own, and acts on attacker-supplied input. When it uses a token outside the audience or scope it was granted — or follows an attacker-chosen URL into cloud credentials — it becomes a deputy tricked into wielding authority it holds but the attacker does not.
Classification
- Domain
- Agentic architecture
- ROOTVIEL support
- Verified by ROOTVIEL — A deterministic, LLM-free verifier settles a specific property under stated assumptions — either a structural property over a graph, or an effect reproduced in execution. It does not by itself mean the whole system is secure, nor that an end-to-end exploit was run beyond what the evidence scope states.
- Evidence scope
- Structural property — Checked over a static authority/dataflow graph — the property holds in the code; no exploit was run.
- Analysis family
- FAM-GENAI-STATIC
- CWE
- CWE-287, CWE-522, CWE-918
- OWASP
- LLM06
Definition
The confused deputy is a classic authorization flaw: a privileged intermediary performs an action on behalf of a less-privileged requester, using the intermediary’s own authority rather than the requester’s. In an agentic system the agent is the deputy — it carries credentials and tokens, and it acts on input an attacker can shape. The attacker cannot reach a resource directly, but the agent can, so the attacker steers the agent into using its authority on the attacker’s behalf.
Two concrete shapes dominate. First, credential misuse: a token minted for one audience or scope is presented to a different resource, so authority granted for purpose A is spent on purpose B. Second, server-side request forgery (SSRF): attacker-chosen input drives the agent to request a URL that reaches an internal endpoint — most dangerously a cloud metadata service that hands back credentials.
Context
Agents accumulate authority to be useful: API tokens, OAuth grants, service-account keys, network reachability to internal services. They also consume untrusted input: user messages, fetched content, tool results. Wherever that untrusted input can choose which credential is used, which resource is targeted, or which URL is fetched, the agent is a candidate deputy.
- ▸An agent that holds a token scoped to one service and can be steered to call another with it.
- ▸An agent that fetches arbitrary URLs and runs in an environment with a cloud metadata endpoint (credential exposure via SSRF).
- ▸A broker that forwards a user request to a backend using its own privileged credential instead of the user’s.
Technical fundamentals
The durable invariants are about matching authority to intent. A token carries an audience (the resource it is for) and a scope (the operations it permits). A confused deputy arises when the audience of the token presented does not match the resource it is presented to, or when the scope of the credential exceeds the scope of the tool that uses it. SSRF is the network-layer version: the "resource" is a URL, and the dangerous mismatch is an outbound request whose destination the attacker chose reaching an endpoint — cloud metadata — that returns credentials.
Because these are matching conditions over known facts (which token, which audience, which resource, which URL target), they are checkable deterministically. The defensive posture that makes the checks meaningful is deny-by-default: a scoped secret store that releases a credential only when the requesting tool’s scope matches the credential’s scope, and an egress policy that blocks requests to credential-bearing internal endpoints unless explicitly allowed.
- Audience
- The resource a token is intended for; the invariant is that it must match the resource the token is presented to.
- Scope
- The operations a credential permits; the invariant is that it must match the scope of the tool using it.
- SSRF to metadata
- An attacker-chosen URL that reaches a cloud instance-metadata endpoint, which returns the environment’s credentials.
Root cause
The defect is that the agent’s authority is ambient and broadly reachable, while the input that directs its use is untrusted — and nothing binds the credential to the specific audience/scope of the action, or the outbound request to an allowed destination. The agent holds more authority than any single action needs, and that surplus authority is addressable by attacker-shaped input. Deny-by-default scoping and audience/scope matching are the missing bindings that would keep the deputy from being confused.
How the attack works, step by step
- 1The agent holds a privileged token or has network reach the attacker lacks.
- 2The attacker supplies input that chooses the target — a resource to call, or a URL to fetch.
- 3The agent presents its token to a resource outside the token’s audience, or spends a broadly-scoped credential on a narrowly-scoped tool call.
- 4In the SSRF variant, the agent fetches the attacker’s URL, which resolves to an internal cloud metadata endpoint.
- 5The resource accepts the mis-scoped token, or the metadata endpoint returns credentials — and the attacker has borrowed the agent’s authority.
Vulnerable example
A synthetic, illustrative agent that presents a single ambient token to any attacker-chosen resource and fetches any attacker-chosen URL:
synthetic — do not use; illustrates the flaw# UNSAFE: one broad token reused everywhere; unrestricted egress. TOKEN = get_service_token() # audience: "billing", broad scope def call_resource(resource_url): # token presented regardless of the resource's audience: return http.get(resource_url, headers={"Authorization": TOKEN}) def fetch(url): # url comes from untrusted input return http.get(url) # can reach http://169.254.169.254/... (metadata) target = user_input["resource"] # attacker chooses the target call_resource(target) # token spent outside its audience fetch(user_input["url"]) # SSRF to cloud credentials
Corrected example
Bind credentials to audience and scope through a deny-by-default scoped secret store, and apply a deny-by-default egress policy that blocks internal/metadata destinations. A credential is released only when the requesting tool’s scope matches the credential’s scope and the target’s audience matches the token’s.
synthetic — deny-by-default scoped secrets + egress policy# SAFER: credentials scoped per audience; egress denied by default. def token_for(resource): cred = secret_store.release(audience=resource.audience, scope=resource.required_scope) # deny-by-default if cred is None: raise Denied("no credential matches this audience+scope") return cred def call_resource(resource): # audience/scope matched before the token is ever presented: return http.get(resource.url, headers={"Authorization": token_for(resource)}) def fetch(url): if not egress_policy.allows(url): # blocks metadata + internal ranges raise Denied("egress destination not allowed") return http.get(url)
Limit of the fix: audience/scope matching and egress denial remove the modelled deputy paths, but they depend on the store knowing each resource’s true audience and the egress policy enumerating the dangerous destinations. A credential whose audience is mislabelled, or an internal range not listed, is outside the guarantee.
Impact
- ▸Authorization: the attacker performs actions with the agent’s privileges that they could not perform themselves.
- ▸Confidentiality: SSRF to a cloud metadata endpoint can hand the attacker the environment’s credentials wholesale.
- ▸Lateral movement: a mis-scoped token accepted by the wrong resource opens services the attacker had no path to.
- ▸Credential compromise: leaked or borrowed credentials persist until revoked, extending the blast radius well beyond the agent.
Detection
The conditions are deterministic matching facts. Static analysis can check, on a proven path, whether a credential is used outside its granted audience or scope, and whether an outbound request driven by untrusted input can reach a credential-bearing internal endpoint (SSRF to metadata). A confirmed finding is a path where the token’s audience/scope does not match the resource it reaches, or where attacker-influenced input flows to a fetch that can resolve to metadata. Absence of such a path over the analysed graph is "no deputy path found in scope".
How ROOTVIEL analyzes it
- Support level
- Verified — the execution engine detects a credential/token used outside its granted audience or scope, and SSRF reaching cloud credentials, on a proven path.
- Family
- FAM-GENAI-STATIC — static dataflow/graph reasoning.
- Declared invariants
- "token audience must match resource" and "credential scope must match tool scope."
The engine checks the two matching invariants over the authority/dataflow graph and separately traces attacker-influenced input to an outbound request that can reach a cloud metadata endpoint. The corrective posture it reasons against is a deny-by-default scoped secret store: a credential is releasable only when the tool’s scope matches the credential’s scope and the token’s audience matches the resource.
Honest framing: a confirmed finding is a proven path where the audience/scope invariant is violated or where untrusted input reaches a metadata-bearing fetch. Where no such path is proven, the verdict is "no deputy path found in the analysed graph" — scoped to the graph’s coverage of audiences, scopes, and egress destinations, not a claim that every credential use is correct.
Mitigation
Bind authority tightly and deny by default on both secrets and egress.
- ▸Preventive: issue narrowly-scoped, audience-bound credentials; release them from a deny-by-default scoped secret store only when tool scope matches credential scope.
- ▸Preventive (network): deny-by-default egress; explicitly block cloud metadata endpoints and internal ranges from agent-driven fetches.
- ▸Preventive (delegation): prefer acting with the requester’s own authority over the agent’s ambient authority where possible.
- ▸Corrective: short-lived credentials, prompt revocation/rotation on suspected leak, and rate-limited scope so a confused deputy’s blast radius is small.
Verifying the mitigation
Verify by re-running the static checks and confirming no proven path presents a token outside its audience, spends a credential beyond the tool’s scope, or routes untrusted input to a fetch that can reach metadata. Complement with synthetic tests: request a resource whose audience does not match the token and confirm the store denies the credential; drive a fetch toward a metadata URL and confirm egress policy blocks it. Report as "no deputy path in the analysed graph; scoped-store and egress denials held in the tested scope".
The checks are only as complete as the labelled audiences, scopes, and the enumerated egress deny-list; an unlabelled credential or an unlisted internal range is outside the guarantee.
Common mistakes
- ▸Giving the agent one broad ambient token and reusing it for every resource regardless of audience.
- ▸Allowing agent-driven fetches with no egress policy, leaving the cloud metadata endpoint reachable.
- ▸Acting with the agent’s privileges on a user’s behalf instead of the user’s own authority.
- ▸Treating a leaked credential as low-impact and deferring rotation, extending the deputy’s reach.
References
- [1]OWASP Top 10 for LLM Applications — LLM06 Excessive Agency
- [2]OWASP Agentic Security Initiative
- [3]MITRE ATLAS
- [4]MITRE CWE-287 (Improper Authentication), CWE-522 (Insufficiently Protected Credentials), CWE-918 (SSRF)
- [5]Model Context Protocol — Specification
References point to public, well-known technical sources for further study.
Related articles
