Back in 1988, a compiler running on a commercial timesharing system had permission to write to a shared directory for recording language feature usage statistics. That same directory also stored the file holding the system's billing records. A user asked the compiler to write its debug output to a file with the same name as the billing file. The compiler, using its own permissions rather than the user's, opened the file and overwrote it.
Norm Hardy wrote up the incident in a 1988 paper and gave it a name: the Confused Deputy problem. It describes a scenario where a program with legitimate authority gets tricked by a less-privileged actor into misusing that authority on the actor's behalf.
Almost forty years later, most developers building software have never heard the term, even though they encounter its cousins constantly. And right now, AI agents are giving it a wider blast radius than Hardy ever imagined.
What Is the Confused Deputy Problem?
Setting aside the mainframe context, the pattern is simple: a deputy (an application or service executing a task) holds permissions its caller doesn't have. The deputy does useful work by relying on those permissions. Somewhere along the way, an attacker gets the deputy to use its own authority for the attacker's benefit instead of the caller's.
Two structural conditions make this possible:
- First, the identifier used to reference an object (a filename, a URL, a resource ID) doesn't carry access rights of its own. Anyone can write down
https://example.com/invoices/1234; writing down the resource's name isn't the same as being allowed to open it. - Second, the deputy's permissions apply automatically, with no explicit step where authority is checked against who's actually asking. The compiler didn't ask "does this specific user have rights to this specific file?" It simply asked "do I have rights to this file?" and got the wrong answer to the right question.
This isn't a single bug. It's a shape that privilege-escalation bugs keep taking, wherever a component with higher privileges processes an insufficiently verified request from a component with lower privileges.
A Problem That Never Went Away
If the compiler story sounds academic, the pattern it describes is everywhere in production systems today.
Cross-Site Request Forgery (CSRF) is a Confused Deputy attack occurring in a browser-based environment. Your browser holds a valid session cookie for your bank. A malicious page gets your browser to submit a form to the bank's transfer endpoint. The bank's server sees a request carrying a valid cookie and processes it, because the cookie is the only thing it checks. Your browser is the deputy; the cookie is the ambient authority; the malicious page is the attacker who never had transfer rights of its own.
A more general version of the same problem shows up in Server-Side Request Forgery (SSRF). Plenty of backend services exist to fetch a resource on a caller's behalf: a link-preview generator, a PDF renderer, a webhook relay, an image proxy. In these scenarios, the caller supplies a URL, and the service fetches it using its own network position and its own credentials. An attacker who supplies the address of an internal endpoint instead of a legitimate image URL gets the service to reach into a place the caller could never reach directly. It hands back whatever secrets that endpoint returns. The service is the deputy, its network access is the ambient authority, and the attacker never had permission to query that endpoint themselves.
Why AI Agents Are the Perfect Deputy to Confuse
An AI agent is a deputy by design. You give it access to your calendar, your GitHub repo, your billing system, so it can act on your behalf without you typing every command yourself. That's the whole value proposition. It's also exactly the setup Hardy described in 1988, reproduced at scale.
What makes agents worse than the 1988 compiler is how they receive instructions. The compiler at least had a fixed, narrow interface: a filename parameter. An agent reads a system prompt, a user request, retrieved documents, tool outputs, and other agents' messages. It processes all of it through the same channel: natural language, tokenized and fed to a model that has no built-in way to mark some tokens "trusted command" and others "untrusted content." A sentence buried in a GitHub issue title carries exactly the same weight to the model as a sentence typed by the person who owns the API key.
That single fact turns Confused Deputy from a rare, hand-crafted exploit into something closer to standard practice for attackers. Getting a 1988 compiler to misuse its authority required knowing the exact filename of a sensitive file and getting a specific user to request it. Getting an agent to misuse its authority just requires putting the right sentence somewhere the agent will read it: an email, a web page, a code comment, a support ticket. Combine that with agents that typically hold a user's full OAuth scope rather than a task-specific slice of it, and you have a deputy that's both easy to confuse and dangerously over-authorized when it happens.
When It's Already Happened
This isn't hypothetical. In February 2026, an authenticated GitHub issue-triage bot with broad repository access and shell execution rights processed a new issue with a crafted title. The title contained an embedded instruction that got the agent to execute an attacker-supplied command inside the triage workflow. Researchers named the technique "Clinejection", after the tool it targeted.
The agent's action wasn't the end of the chain, just the entry point. The attacker used that first foothold to flood the project's shared GitHub Actions cache with junk data, forcing out legitimate cache entries and replacing them with poisoned ones matching the keys used by a separate, much more privileged nightly release workflow. When that workflow ran, it restored the poisoned cache, handing the attacker execution inside a job that held the project's npm publishing token. With that token, the attacker published a tampered package version whose install script silently pulled down an unrelated AI agent tool onto every machine that installed the update. The compromised package was downloaded roughly 4,000 times during the roughly eight-hour window before it was caught.
Look at where the actual damage came from. Not from a flaw in the language model. From an agent that couldn't distinguish an issue title from an instruction, combined with credentials and cache access that assumed anything running inside a trusted workflow was, by definition, trustworthy. That's the Confused Deputy pattern end to end: legitimate authority, an under-verified request, and a chain of systems willing to act on the deputy's behalf without checking who actually asked.
Security researchers are already tracking related patterns in MCP tool servers (where a malicious tool description can inject instructions the calling agent treats as legitimate) and in multi-agent systems, where one agent re-delegates a task to another without re-verifying that the original request actually authorized it. The pattern is the same each time: a channel that mixes instructions with data, and a deputy that acts on whatever arrives through it.
The Old Playbook Still Works
None of the fixes for Confused Deputy attacks are new, and that's good news. The same principles that protect fetch services and browser sessions apply directly here:
- Least privilege means giving a deputy only the authority it needs for the task in front of it, not a standing grant sized for every task it might ever perform.
- Capability-based security takes this further: instead of an identifier (a filename, a userId, a URL) that relies on the deputy's ambient permissions to resolve, you hand the deputy a token that bundles the object reference and the access right together. The deputy can't be tricked into misusing authority it was never actually given, because the authority travels with the request instead of living separately inside the deputy. In practical terms, this means checking audience, scopes, and permissions in access tokens, but also using fine-grained authorization tools.
- Explicit permission transfer replaces the automatic inheritance that got the 1988 compiler in trouble: instead of "I have write access to this directory, so any request I process gets that access," the system requires "this specific caller granted this specific permission for this specific action." Token Exchange, in its various facets, helps implement this requirement.
What Changes When the Deputy Is an AI Agent
Applying that playbook to agents means translating each principle into something that survives an agent's specific failure mode: since it can be convinced of anything, the authorization has to hold even when the agent's judgment doesn't.
Standing OAuth scopes that an agent holds for its entire session are the equivalent of the compiler's blanket write access to the shared folder. Task-scoped, short-lived credentials fix this the same way least privilege does: an agent gets exactly the access it needs for the task at hand, and that access expires when the task ends, rather than persisting as a standing grant an attacker can hijack days later.
Broad verbs like billing:write or email:send are also too coarse. If an agent can call billing:write, a single successful injection lets an attacker do anything billing-related. Capability-scoped permissions narrow that surface to specific business actions, "issue a refund under $50," "send an email to an address already in this thread," so even a fully confused agent has a small, well-defined blast radius.
Credentials themselves need to live somewhere the model can't reach. If a token sits in a system prompt or a tool schema so the model "knows what to pass," it's also sitting in the exact place a prompt injection payload can extract it. The reliable pattern is to keep the model in charge of deciding what to do (which tool, which parameters, based on the user's request) while a separate, deterministic layer of code executes the action and holds the credential. The model never sees a token it could be tricked into revealing or misusing, because it never has one.
And for anything expensive, irreversible, or broad enough to matter, human-in-the-loop approval puts a checkpoint between the agent's decision and the action actually happening: a specific, out-of-band confirmation for the specific action requested, not a blanket yes/no given once at the start of the session.
Where Auth0 Fits
This is the shift Auth0 for AI Agents is built around: moving agents away from standing, broadly scoped credentials and toward access that's narrowly scoped to a task, short-lived, and traceable back to the specific agent and request that used it, with a human approval step available for anything above a defined risk threshold. Token Vault issues just-in-time tokens for third-party APIs instead of handing agents standing credentials to store and reuse, and Auth0's work on treating agents as first-class identities and on scoping authorization to a task's actual intent both aim directly at closing the gap this post has been describing. None of it requires you to trust the agent's judgment more. It requires trusting it less, by design.
The Bug Doesn't Care How New Your Stack Is
Confused deputy isn't a vulnerability class that AI introduced. It's a vulnerability class AI agents are reintroducing at a scale Norm Hardy couldn't imagine in 1988: millions of deployed deputies, each reachable by anyone who can write a sentence into content the agent will eventually read.
The fix hasn't changed either. Stop treating an agent's ambient access as proof that a specific request is legitimate. Every credential you hand an agent should be a specific, auditable capability, scoped to a task and expiring when the task ends, not a blanket delegation you hope the agent uses responsibly. Hardy's compiler didn't have a choice about how it used its authority. Your agent shouldn't be given the chance to have one either.
What's the broadest standing permission your agents currently hold that you'd have a hard time explaining to a security reviewer? That's the first one worth narrowing.
About the author
Andrea Chiarelli
Principal Developer Advocate
I have over 20 years of experience as a software engineer and technical author. Throughout my career, I've used several programming languages and technologies for the projects I was involved in, ranging from C# to JavaScript, ASP.NET to Node.js, Angular to React, SOAP to REST APIs, etc.
In the last few years, I've been focusing on simplifying the developer experience with Identity and related topics, especially in the .NET ecosystem.
