Know the attacks
The confused deputy problem in AI agents
An agent with broad credentials that takes orders from any text it reads can be talked into using those credentials for the wrong person.
New to MCP? What is an MCP server? covers the basics first.
A confused deputy is a program with legitimate access that gets talked into using it for someone who was never given that access. Nothing is stolen and nothing is hacked. The program does exactly what it was built to do, for the wrong requester.
In an AI agent, the deputy is the agent and its access is whatever token it was set up with. The wrong requester can be a user with less access than the agent, or an instruction hidden in something the agent reads.
Where the term comes from
Norm Hardy described it in a short 1988 paper, The Confused Deputy. At Tymshare, a Fortran compiler had write access to a system directory so it could log its own usage there. The billing file lived in the same directory. A user asked the compiler to write its debug output to a file named after the billing file, and the compiler, using its own access instead of the user's, overwrote the billing data.
Hardy's point was that the compiler held two kinds of authority, the user's and its own, and had no way to keep them apart. A filename from a less-privileged user got used with the compiler's more-privileged access.
The agent version
An agent is a deputy by design. You give it access so it can act for you, and that access is usually one credential good for everything the connection allows.
What makes an agent easier to confuse than a 1988 compiler is its input. The compiler took a filename. An agent reads system prompts, user messages and tool output through one model, with no built-in way to mark which parts came from its operator. A sentence in an issue title can carry as much weight as one from the person who holds the key.
There's a real case. On December 21, 2025, the Cline project added a GitHub Actions workflow where an AI agent triaged new issues, with bash execution enabled and any GitHub user allowed to trigger it. Researcher Adnan Khan found that an issue title could carry an instruction telling the agent to run npm install against an attacker's commit. Snyk's writeup traces how that could poison the shared Actions cache and reach a nightly release workflow that held the project's npm publishing token. An unauthorized version of the package was later published, and GitHub tracks it as GHSA-9ppg-jx86-fqw7.
No credential was stolen to start it. The triage agent used the access it was configured with, for a requester (anyone with a GitHub account) who was never meant to have it.
What the MCP spec says
The MCP security best practices page names the confused deputy problem for one setup in particular: an MCP server acting as an OAuth proxy to a third-party API with a single static client ID. An attacker can use a user's leftover consent cookie to approve a malicious client without the user seeing a prompt. The fix it gives is per-client consent tracked on the server.
It also forbids token passthrough, where a server takes a client's token and forwards it to another API unchecked. MCP servers "MUST NOT accept any tokens that were not explicitly issued for the MCP server." Passthrough has the same root cause as Hardy's compiler. A credential ends up working for a caller nobody checked.
Defenses
The question the compiler should have asked was "is the person who called me allowed to touch this file?", not "am I allowed to?". The same goes for a tool call.
So give every caller its own identity. If a person and an agent share a token, nothing downstream can tell who acted. Scope each agent's credential to its job instead of to everything it might ever do, and check the audience on every token a server accepts.
None of this stops an agent from being talked into misusing access it legitimately has. It limits how much one confused request can do.
Where Statio fits
Statio treats each agent as its own principal, with its own grants, a short-lived token and its own lines in the activity log. A call the agent makes is never logged as if a person made it, and you can suspend one agent without touching anyone else.
Per-tool permissions let you grant an agent a server while denying the one tool it has no business calling, like merge_pull_request. Every call and refusal goes to the audit log, so afterwards you can see which agent called what.