Lesson 6 of 12 · 7 min read
The Confused Deputy
In this lesson
TL;DR: A confused deputy holds authority (the deputy) and is tricked by a less privileged party into using it for them. The root cause is ambient authority: the deputy acts with its own permissions no matter who asked. Fixes make the authority travel with the request: act with the requester's credentials or a token scoped to them, check who the action is for, and refuse tokens or requests not meant for you. AI agents are deputies by design, and prompt injection is the trick.
Before you read
Pick an answer before you read further. The lesson below explains it, and guessing first, right or wrong, helps the explanation stay with you.
1A file-conversion service runs with permission to write anywhere in a shared storage bucket. Users pass it an input path and an output path. What can a malicious user do?
The original story
Norm Hardy described the problem in 1988. A compiler on a timesharing system had permission to write a billing file, so it could record usage. Users could tell the compiler where to write its debugging output. A user named the billing file as the output path, and the compiler, using its own authority, overwrote it. The compiler was not malicious and not broken in the usual sense. It was confused about whose authority it was exercising.
The paper is short and worth citing correctly: Norm Hardy, "The Confused Deputy (or why capabilities might have been invented)", ACM SIGOPS Operating Systems Review, volume 22, issue 4, October 1988. The system was at Tymshare, and the subtitle is the point: the fix Hardy argued for was capabilities, where the permission travels with the request.
The pattern
Three ingredients make a confused deputy:
- A deputy with authority the requester lacks.
- A requester who can influence what the deputy does: a parameter, a path, a URL, a message.
- Ambient authority: the deputy acts with all its permissions regardless of who asked.
Once you know the shape, it appears everywhere:
| Setting | Deputy | Trick |
|---|---|---|
| Web server fetching URLs (SSRF) | Server with internal network access | User supplies an internal URL |
| Cloud service acting for customers | Service with cross-account roles | Customer A names customer B's resource |
| OAuth proxy or API gateway | Service holding tokens | Passes a token to a service it was not issued for |
| AI agent | Model plus the tools and credentials it holds | Injected text instructs it to use them |
The cloud version, precisely
AWS documents two confused deputy cases and a control for each, and they are the clearest real-world illustration of the pattern.
Cross-account. A SaaS vendor reads customers' AWS accounts by assuming a role each customer creates. Role ARNs are not secret. Without a further check, customer B could give the vendor customer A's role ARN, and the vendor, using its own credentials, would read A's account for B. The control is an external ID: the vendor generates a unique value for each customer, the customer's role trust policy requires sts:ExternalId to equal it, and the vendor always sends the value it issued to whichever customer is making the request. The customer must not choose the value, or B could simply copy A's.
Cross-service. When a resource such as an S3 bucket trusts an AWS service principal, say CloudTrail writing logs, any account using that service could direct it at the bucket. The control is a condition on whose behalf the service acts: aws:SourceArn, aws:SourceAccount, aws:SourceOrgID or aws:SourceOrgPaths, which can be applied across an organisation with resource control policies. Google Cloud's workload identity federation has an equivalent: attribute conditions that reject credentials issued for other workloads, which Google describes as mitigating the confused deputy problem.
Worked example: the cost dashboard
A cost dashboard vendor assumes arn:aws:iam::111122223333:role/CostRead to read customer A's billing data. Customer B signs up and enters A's role ARN.
Trust policy without an external ID
B registers A's role ARN
Vendor assumes the role with its own credentials
ambient authority
B's dashboard shows A's costs
Outcome, unsafe: Cross-customer data leak
The vendor's authority served the wrong customer.
Trust policy requires a vendor-issued external ID
B registers A's role ARN
Vendor sends B's external ID
A's policy expects A's ID
AssumeRole is refused
Outcome, safe: Request bound to the requester
The vendor can only act for the customer it issued the ID to.
Ambient authority
The vendor can assume any role that trusts it, so whoever names the role directs that authority.
An AI agent holding one API key that serves 500 tenants has exactly the same shape. The fix there is a per-tenant, per-user token obtained through token exchange, so each call carries the authority of the person it serves.
Agents: the most capable deputies yet
An agent with access to email, files and internal APIs holds more authority than most single services, and it takes instructions in natural language from many sources: the user, documents, web pages, tool results. Prompt injection is the confused deputy attack aimed at that deputy. The question is never only "did the model follow the instruction?" but "whose authority did the resulting action use?"
Web page
Written by anyone
Agent
The deputy
Admin API
Accepts agent's key
Also in the picture
User
- Asked for a summary
User's docs
- User's own token
Ambient authority
The agent holds a powerful service key. Text on a web page asks it to call the admin API, and the API accepts the agent's key whoever was behind the request.
Delegation is not impersonation
OAuth token exchange (RFC 8693) distinguishes two modes, and the difference matters for agents. In impersonation, the issued token makes the actor indistinguishable from the subject: downstream systems see only the user. In delegation, the token names the user as subject and records the actor in an act claim, and a may_act claim can state in advance who is allowed to act for whom. Delegation keeps an audit trail and lets the resource server apply rules to the agent as well as the user. For agents, prefer delegation.
Chains of deputies
Multi-agent systems create chains: agent A calls agent B, which calls a payments API. Each hop is a deputy. Three rules keep the chain from accumulating authority:
- Each hop obtains a new token by exchange, with an audience for the next service only and a scope no wider than it needs.
- Authorization downstream uses the top-level subject (the user) and the current actor; earlier actors in nested
actclaims are history, not grants. - No hop passes its incoming token onward. The Model Context Protocol forbids exactly this for MCP servers, and OAuth's security best current practice (RFC 9700) requires resource servers to refuse tokens not issued for them.
User
Full own rights
Agent A
sub=user, act=A
Agent B
sub=user, act=B
Payments API
Checks user and B
Start from the user
The chain begins with the user's authority, never with an agent's own broad credentials.
Deputies that fetch URLs
Any server that fetches a URL it was given is a potential deputy, because it fetches with its own network position. That includes the obvious cases, such as webhooks and link previews, and less obvious ones: JWT headers such as jku and x5u point to where a key should be fetched, and RFC 8725 warns they can be used for server-side request forgery. Allowlist destinations, fetch from a separate network identity with no internal reach, and never fetch keys from locations named in the token itself.
Fixes
Carry the requester's authority, not the deputy's. Act with the user's delegated credentials, scoped to the task, so downstream systems authorize as the user. OAuth token exchange (RFC 8693) lets a service obtain a narrower token for a downstream call on a user's behalf.
Check whose resource it is. A service that acts for many customers must verify the target belongs to the requester. Cloud providers use mechanisms such as external IDs and source-account conditions on cross-account roles for exactly this reason.
Refuse tokens not meant for you, and do not pass tokens through. A server should accept only tokens whose audience is itself, and should not forward a client's token to other services. The Model Context Protocol's security guidance forbids token passthrough for this reason (checked November 2026).
Capabilities over ambient authority. In capability-based designs, a request carries an unforgeable reference that is itself the permission ("write to this file"), rather than a name the deputy resolves with its own rights. Pre-signed, single-object URLs are a familiar example.
For agents, add the AI-specific layers. Separate tools by trust, require approval for sensitive actions, and break the lethal trifecta so a deputy that does get confused has nowhere harmful to send what it reads.
Capabilities in practice
Hardy's preferred fix survives in familiar forms: a pre-signed URL that grants access to one object for a few minutes; attenuated tokens, such as macaroons, where any holder can add restrictions but nobody can remove them; and exchanges gated by may_act that issue a short-lived token for one task. Each carries the permission with the request instead of asking the deputy to resolve a name with its own rights.
Misconceptions interviewers listen for
- "Role ARNs are secret." AWS says they are not; that is why external IDs exist.
- "The deputy needs better input validation." The root cause is ambient authority; validation narrows the inputs but leaves the authority.
- "Impersonation and delegation are the same." Delegation keeps the actor's identity visible; impersonation hides it.
- "Prompt filtering fixes agent confused deputies." Scoping the agent's authority does.
What if · interview follow-ups
Hold your answer as the constraints change
You are reviewing a SaaS platform that reads customers' cloud accounts, fetches webhooks, and runs AI agents that call each other and a payments API. The interviewer looks for confused deputies.
Start here
The webhook service fetches user-supplied URLs from inside the network. Where is the deputy?
Whose network position does the fetch use?
The webhook fetcher is the deputy: it uses its own network position to fetch whatever a user names, which is server-side request forgery. Allowlist destinations, resolve and check addresses at fetch time, and run the fetcher under a separate network identity that cannot reach internal services or cloud metadata.
Carry it forwardFetching on someone's behalf should use authority that has no internal reach.
Weak answerRelying on a blocklist of internal hostnames.
Constraint changes
How do you stop customer B from directing your cross-account access at customer A?
Who chooses the value that binds a role to a customer?
Require a vendor-generated external ID per customer in each role's trust policy, and always send the ID issued to the customer making the request. Role ARNs are not secret, so the binding must come from a value the vendor controls. The customer must not choose it, or B could copy A's.
Carry it forwardBind each delegated role to the requester with a vendor-issued value.
Weak answerTreating the role ARN as a secret.
Constraint changes
A central log bucket trusts the logging service with no conditions. What is the risk?
On whose behalf does the service write?
Any account using that service could direct it to write into, or read through, the bucket. Add conditions on the source account or organisation, such as aws:SourceAccount or aws:SourceOrgID, and apply them centrally with resource control policies so new buckets inherit them.
Carry it forwardService principals need conditions on whose behalf they act.
Weak answerTrusting the service principal because it belongs to the cloud provider.
Constraint changes
Agent A calls agent B, which calls the payments API. How do you keep authority from growing along the chain?
Exchange, narrow, decide on subject and actor.
Each hop exchanges for a new token with the user as subject and itself as actor, an audience of the next service only, and a narrower scope. The payments API authorizes on the user and the current actor, ignoring earlier actors except for audit. No hop forwards its incoming token.
Carry it forwardEvery hop narrows authority; nothing is passed through.
Weak answerLetting agents share one service key for convenience.
Constraint changes
A token for your MCP server arrives with an audience naming another API. What do you do?
Whose token is it?
Reject it: a resource server must refuse tokens not issued for it. If your server needs to call that other API for the user, it performs its own exchange to get a token for that audience. Accepting or forwarding the token would make your server a deputy for whoever obtained it.
Carry it forwardAccept only tokens issued for you; exchange for anything downstream.
Weak answerAccepting it because the signature is valid.
Now defend it
As the defender, what evidence would show a confused deputy being exploited?
AssumeRole failures on external ID mismatches, requests where the requester and the target resource belong to different tenants, outbound fetches to internal or metadata addresses, tokens rejected for wrong audience, and agent actions whose recorded user differs from the session that triggered them.
How this shows up in interviews
Expect the term in agent design rounds, sometimes directly: "what is a confused deputy and how does it show up in agents?" Strong candidates tell the 1988 story in one sentence, define ambient authority, give a modern example (SSRF, an MCP server forwarding tokens, an agent with a service account), and then show the fix as a design property: the action carries the requester's authority, and the downstream system checks it.
Say it in 30 seconds: "A confused deputy is a privileged program tricked into using its authority for someone who lacks it, because it acts with ambient authority whoever asked. SSRF is one, an OAuth proxy that passes tokens through is one, and an agent with a broad service key that reads a malicious web page is the modern one. The fix is to make authority travel with the request: act with the user's scoped token, check the target belongs to the requester, and only accept tokens issued for you."
Check yourself
Say or write your answer first, then reveal. Explaining it from memory, in your own words, is the skill an interviewer is checking.
1An MCP server receives a user's token from the agent and forwards it unchanged to a third-party API. What is wrong?
2Why is 'the agent only follows the user's instructions' not a fix for the confused deputy problem?
3Why must an AWS external ID be generated by the vendor rather than chosen by the customer?
4What is the difference between delegation and impersonation in RFC 8693?