The confused deputy, or why "just forward the token" breaks your MCP server
Yimmie HonrodtDEV Community
1 views
Here is a failure that does not look like a bug in code review, passes every test you wrote, and quietly hands an attacker your privileges. It is called the confused deputy, and it is the reason "just forward the token" is one of the most expensive shortcuts you can take in an MCP server.
The deputy, in one paragraph
A deputy is a program that acts for other people while holding more authority than they do. A confused deputy is one that can be talked into using that authority for a request it should have refused. Your MCP server is a deputy by design: it sits between an AI client and your downstream systems, and it usually holds broad credentials for those systems.
It arrives in two shapes
Shape 1: token passthrough
The client sends a token, your server forwards that same token unchanged to a downstream API.
The downstream system trusts your server, so the call goes through.
Your server never asked whether this caller was allowed to do this thing.
Your audit log records "the server did it". The actual actor is invisible.
Shape 2: accepting foreign-audience tokens
Your server accepts a token whose audience was issued for a different service. Anyone who can obtain such a token, for any service you happen to accept, can now drive your server.
The MCP specification does not hedge on either shape. Servers "MUST only accept tokens that are valid for use with their own resources" and "MUST NOT accept or transit any other tokens". If the server calls an upstream API, it acts as an OAuth client to that API, with a separate token of its own.
Why it ships by accident
Three reasons, and none of them is carelessness.
Libraries make passthrough the path of least resistance. It works in every happy-path test, because the happy-path caller genuinely is authorized. And the gap only appears with a caller who should not be authorized, which is exactly the case nobody writes a test for.
There is a variant that catches proxy authors specifically. If your server sits in front of a third-party authorization server with a static client ID, a user who consented once may never see a consent screen again, and a stolen authorization code can be redeemed on their behalf. That is why the spec requires consent per dynamically registered client rather than once per proxy.
How to find it in your own code
Trace where downstream calls get their credentials. If the answer is "the incoming token", you have shape 1.
Check whether the server validates the audience against its own canonical resource URI. If it does not, you have shape 2.
Prove it. Take a token minted for another audience, or another tenant, and make a tool call. It has to fail.
How to fix it
Validate the audience strictly. The token has to be for you.
Authorize per call against the actual end user and tenant, not merely "is this token valid". There is no protocol-level session to lean on, so per-request is the only granularity there is.
Use your own credentials, or a token exchange, for downstream calls, so the audit trail can name the real actor.
Log actor, tenant, tool and outcome. A passthrough design structurally cannot produce a truthful audit log, and that is the part that hurts six months later when somebody asks what happened.
Forwarding the token buys you five minutes and sells an invisible privilege-escalation path. Treat the server as a deputy that re-checks authority on every single call, for the specific caller, and never lends its keys to a request it did not verify itself.
One thing an outside scan can tell you, and one it cannot. It can check whether your protected resource metadata declares a resource at all, because without a declared audience no client can bind a token to you and the whole defence never gets off the ground. It cannot watch what your server does with the token afterwards. That part needs the code, or somebody who reads it.
The metadata half is in my scanner: mcp-sec-scan.
Hello, I’m simply asking because I’m aspiring to become a web developer, and I’m curious about how viable the field is nowadays. I don’t think you can really blame people for asking this either, because front-end development has been heavily trivialised by AI(not my opinion), or at least that’s what
Project Name: Podcode Repo/Website Link: https://podcode.io Description: Quick background, since this matters for the rest. I run a small private AI stack for my own work. Coding agents like Claude Code and Codex are part of my daily flow. They are great when they work. The thing that drove me nuts
ChatGPT.com reached about 1.09 billion monthly US visits in July 2026, a 48.38% year-over-year increase, according to Semrush Traffic Analytics data. In the same comparison, Bing.com traffic fell about 50.43%. The contrast does not show AI replacing conventional search overnight. Google and YouTube