The short answer
Token passthrough is when an MCP server takes a token from the client and forwards it to a downstream API without checking the token was issued to the MCP server. The MCP spec forbids it: “MCP servers MUST NOT accept any tokens that were not explicitly issued for the MCP server.”1
The confused deputy is an attack on MCP servers that proxy a third-party API using one static OAuth client ID. If the third-party server remembers consent with a cookie and the proxy lets clients register dynamically, an attacker can get an authorization code for the victim’s account without the victim seeing a consent screen. The spec’s fix: proxy servers MUST implement per-client consent before forwarding to the third party.1
Both matter most for remote MCP servers that act on a user’s behalf against GitHub, Google, Slack or similar APIs.
Deedglass
A tool call meets your rules before it runs
Asks to run
DELETE FROM visits;
Deletes every row in visits
Deedglass checks your rules
- Reading dataAllowed
- Deleting a whole table (DROP, TRUNCATE)Never
- Changing or deleting rows without saying which (WHERE)This one
- Other changesWait for a person
Token passthrough: what it is
Picture an MCP server for a project-management API. The tempting design is: the client already has a token for the project API, so it sends that token to the MCP server, and the MCP server forwards it with each API call. No OAuth flow of its own. Simple.
The spec calls this an anti-pattern: the server accepts tokens without validating they were properly issued to it, and passes them through to the downstream API.1 The correct design is that the MCP server is its own OAuth resource: clients get tokens whose audience is the MCP server, the server validates them, and the server uses its own credentials or a separate, properly issued token for the downstream API.
Why it’s forbidden
The spec lists the risks. In short:1
| Risk | What goes wrong |
|---|---|
| Security controls get skipped | Rate limits, request validation or monitoring that depend on the token’s audience don’t apply when a client can use a token meant for another service |
| Accountability breaks | The MCP server can’t tell its clients apart when they all present upstream tokens it can’t read, and the downstream API’s logs show a different identity from the one actually calling |
| A stolen token gets a proxy | If the server forwards tokens without checking their claims, someone holding a stolen token can use the server for data exfiltration |
| Trust spreads | A token accepted by several services without validation lets an attacker who compromised one reach the others |
| It’s hard to fix later | A “pure proxy” that later needs controls has to redesign its token handling |
For agents, the accountability row is the one that bites in an incident. If an agent did something through your MCP server and every request carried the same upstream token, you can’t answer “which client, which user, which session?” from the server’s side.
The confused deputy, step by step
The attack needs four conditions together:1
- The MCP proxy server uses a static client ID with the third-party authorization server.
- The proxy lets MCP clients register dynamically, each getting its own client ID.
- The third-party authorization server sets a consent cookie after the first authorization.
- The proxy doesn’t do its own per-client consent before forwarding to the third party.
Then:1
| Step | What happens |
|---|---|
| 1 | The user connects a legitimate client through the proxy and approves access at the third party. The third party sets a consent cookie for the proxy’s static client ID. |
| 2 | The attacker dynamically registers a new client with the proxy, with a redirect URI on the attacker’s server. |
| 3 | The attacker sends the user a link with a crafted authorization request for that new client. |
| 4 | The user clicks. Their browser still holds the consent cookie, so the third party skips its consent screen. |
| 5 | The proxy completes the flow and redirects the MCP authorization code to the attacker’s redirect URI. |
| 6 | The attacker exchanges the code for an MCP token and calls the third-party API as the user. |
The “deputy” is the proxy: it holds legitimate authority (the static client ID the user approved) and is tricked into using it for someone else. The third party’s consent screen can’t help, because from its point of view the request came from the same client the user already approved.
What a proxy server must do
The spec’s required protections, condensed:1
Per-client consent. Keep a registry of approved client IDs per user, check it before starting the third-party flow, and store decisions server-side or in server-specific cookies.
A consent page the proxy owns. It must name the requesting MCP client, show the third-party scopes requested, show the registered redirect URI, protect against CSRF, and refuse to be framed (frame-ancestors or X-Frame-Options: DENY).
Consent cookies done properly, if used: __Host- prefix; Secure, HttpOnly and SameSite=Lax; signed or server-side; bound to the specific client ID, not just “this user consented.”
Exact redirect URI matching. The redirect URI must match the registered one by exact string comparison, with no wildcards or patterns, and a changed URI needs re-registration.
A real state parameter. Random per request, stored only after consent is approved, set immediately before redirecting to the third party, validated exactly at the callback, single-use and short-lived (the spec suggests around 10 minutes). Setting the state cookie before consent makes the consent screen useless, because an attacker can craft a request that skips it.
A review checklist
Use this when you build or adopt a remote MCP server that calls another API for the user:
- The server validates every token’s audience and rejects tokens not issued for it.
- The server never forwards the client’s token to the downstream API.
- Downstream calls use credentials obtained by the server’s own OAuth flow.
- If the server uses one static client ID upstream, it shows its own consent page per MCP client.
- The consent page names the client, the scopes and the redirect URI.
- Redirect URIs are matched exactly.
-
stateis random, single-use, short-lived, and stored only after consent. - Consent cookies are
__Host-,Secure,HttpOnly,SameSite=Laxand bound to the client ID. - Requested scopes are minimal; the spec lists publishing every scope and using wildcard scopes as common mistakes.1
Tokens decide who the server acts as. They don’t decide what an agent does with that power once connected. Rules on the tool calls themselves sit in front of the server, in an MCP gateway; MCP server security basics covers the other risks, and we compare gateways in MCP gateways compared.
To see what the MCP servers configured on your machine can change, paste the config into the check page or run npx deedglass scan (how the grade works); to try the checks in your browser first, open the playground.
Questions people ask
Is token passthrough allowed in MCP?
No. The security best practices say servers MUST NOT accept tokens not explicitly issued for them, and note that the authorization specification forbids passthrough.1
Which MCP servers are exposed to the confused deputy attack?
Proxy servers that use a static client ID upstream, allow dynamic client registration, sit in front of a third party that remembers consent with a cookie, and skip their own per-client consent.1
Does stdio transport have this problem?
These two attacks are about OAuth flows, which remote (HTTP) servers use. A local stdio server has different risks, such as the command it runs at startup.
Written with AI assistance and checked against our claims register.