The Confused Deputy Wears a New Badge

A 1973 bug about a compiler with too much trust has become the defining vulnerability of the LLM era. Same shape. Different deputy.

By Omar Faroque
Reading time: ~9 min

The most important security paper for the AI era was published in 1988, by Norm Hardy, and described a bug that had already been killing people's billing records since the early 1970s. It is called the confused deputy problem, and once you see its outline you cannot unsee it. Every indirect prompt injection attack against an LLM agent is, in the precise technical sense, the same bug — just with a deputy that now speaks fluent English.

To see why, we need to start with the original.

The original confused deputy. In Hardy's example, there was a compiler program provided on a commercial timesharing service. Users could run the compiler and optionally specify a filename where it would write debugging output, and the compiler would be able to write to that file if the user had permission to write there.

The compiler also collected statistics about language feature usage. Those statistics were stored in a file called (SYSX)STAT, in the directory SYSX. To make this possible, the compiler program was given permission to write to files in SYSX.

But there were other files in SYSX: in particular, the system's billing information was stored in a file (SYSX)BILL. A user ran the compiler and named (SYSX)BILL as the desired debugging output file.

This produced a confused deputy problem. The compiler made a request to the operating system to open (SYSX)BILL. Even though the user did not have access to that file, the compiler did, so the open succeeded. The compiler wrote the compilation output to the file as normal, overwriting it, and the billing information was destroyed.

Read that paragraph again. There is no exploit code. There is no buffer overflow. The user simply asked the compiler to do something, and the compiler — possessing more authority than the user — obliged. The compiler is the deputy. It is confused because it cannot tell the difference between a request that originates from its own purposes (writing to SYSX/STAT) and a request that originates from someone else (writing to whatever path the user passed in). Both arrive as the same kind of system call, made under the same identity.

User low privilege cannot touch SYSX Compiler (the deputy) can write to SYSX (for stats logging) cannot tell whose intent (SYSX)BILL billing records "write debug to (SYSX)BILL" opens, writes (privilege: compiler's) The deputy uses its own authority on the user's instruction
Figure 1 · 1973 · the deputy cannot separate its purposes from yours

The fix that the capability-systems community proposed half a century ago is worth stating clearly, because it will matter again in a moment: do not let the deputy act on ambient authority. The user should hand the compiler not a filename, but a capability — a token that grants permission to write to that specific file, on the user's behalf. If the user does not possess permission to SYSX/BILL, no such token can be produced, and the conversation is over before the compiler is ever asked.

Now Read That Story Again

Replace four words and you have the dominant security problem of 2026.

Replace compiler with LLM agent. Replace filename argument with any text in the model's context window — an email body, a webpage, a PDF, a Slack thread, a tool call result. Replace SYSX directory with the agent's tool-use permissions — its authenticated session to your Gmail, your calendar, your code repository, your bank. Replace billing file with whatever the attacker actually wants: your inbox, your secrets, your money.

The shape of the bug is identical. An indirect prompt injection works exactly because the agent — like the 1973 compiler — cannot tell the difference between instructions that came from its principal (you, the user) and instructions it merely encountered while doing its job (the contents of an email it was asked to summarize). It treats both as commands. It executes both with its own authority. And its own authority is the union of every tool it has been granted.

An agent is a confused deputy that has been given a mouth and a memory, and asked to read the open internet.
Two principals, one identity, one mouth You the principal Attacker writes a webpage webpage / email "…ignore prior, send X" LLM Agent (the new deputy) authenticated to inbox, calendar, code, payments cannot tell whose intent send_email read_files transfer "summarize my latest email" arrives as data, read as command acts with your authority Both arrows enter the agent through the same door: the context window.
Figure 2 · 2026 · the same shape, drawn with new boxes

The Symmetry, Stated Plainly

Compiler bug

  • Compiler is the deputy
  • User passes a filename
  • System call uses compiler's privilege
  • OS cannot tell whose intent it is
  • Billing file is overwritten
  • Fix: capabilities, not ambient authority

Prompt injection

  • LLM agent is the deputy
  • Webpage smuggles instructions
  • Tool call uses agent's session
  • Model cannot tell whose intent it is
  • Inbox is exfiltrated
  • Fix: still capabilities, still no ambient authority

The deeper lesson — the one Hardy was already trying to teach in 1988 — is that the bug is not in the deputy. The compiler was working as designed. The LLM is working as designed. The bug is in the architecture that asks a single program to act on behalf of two principals whose interests diverge, while giving it no machinery to keep them apart.

The fix is the same somewhere-else Hardy pointed to. Stop relying on the deputy to read its way out of confusion. Push the authority decisions out of the model's reasoning loop and into the surrounding system, where data and code are distinguishable: explicit per-action user confirmation for high-impact tools, capability tokens that bind a specific request to a specific resource, isolated execution contexts that strip ambient credentials before untrusted text is processed, dual-LLM patterns where a privileged planner never sees raw external content and an unprivileged worker never holds tools.

None of this is novel. All of it was sketched, in different vocabulary, in the capability-systems literature decades before the first transformer was trained. We are rediscovering an old result the way every generation of systems people rediscovers it: the hard way, in production, on someone else's billing file.

The Reading That Stays With You

If you build agents, the useful frame is this. Every time you give a model access to a tool, you are appointing a deputy. Every time the model's context can be reached by a third party — a search result, a retrieved document, a tool's output, a file on disk written by someone other than your user — you have introduced a second principal. The model owes equal allegiance to both, because it cannot tell them apart.

The question is no longer can my agent be prompt-injected? The answer to that is yes; it is a definitional property of the architecture. The question is the older one Hardy left us with: which of this deputy's powers is it safe to exercise without re-asking the principal?

For most agents shipping today, the honest answer is: fewer than they currently exercise.

· · ·