Token Mis-redemption Across MCP Servers
Token Mis-redemption Across MCP Servers
Summary
When OAuth access tokens issued for one MCP server can be replayed at another, a malicious MCP server can steal a token and present it to a more privileged service — a classic “confused deputy” attack. The fix is RFC 8707 Resource Indicators, which bind a token to a specific audience so that other servers must reject it. The MCP specification introduced resource indicators in its 2025-06-18 revision and the 2025-11-25 revision (the current live spec at time of writing) makes them MUST-level mandatory for MCP clients, alongside an explicit prohibition on token passthrough. The March 2026 spec updates are commonly cited as the point at which RFC 8707 became non-negotiable.
How it works
In the OAuth 2.1 flow used by MCP:
- The MCP client authenticates the user and requests a token from an authorization server.
- The authorization server issues an access token the client then presents to an MCP server to call tools.
Without resource indicators, a token requested for “Photos MCP” could be presented to “Documents MCP” if both trust the same authorization server. Two distinct failure modes follow:
Confused deputy. A malicious (or compromised) MCP server receives a user’s token during a legitimate call, then replays it at an unrelated high-privilege server that happens to accept tokens from the same issuer. The second server — the “deputy” — acts on behalf of the attacker thinking it has user consent.
Token passthrough. An MCP server forwards the incoming token, unchanged, to a downstream API it proxies. If the downstream API checks only signature and expiry, it accepts the token as if it had been issued directly for itself, bypassing audience checks and the MCP server’s own rate-limiting and audit trail.
RFC 8707 mitigates both by adding a resource parameter to the authorization and token requests. The authorization server embeds an aud claim scoped to that resource, and every MCP server must reject any token whose aud is not itself.
without RFC 8707: with RFC 8707:
client ─token(any)─► server A client ─token(aud=A)─► server A [ok]
server A ─replay─► server B [accepted] server A ─replay──► server B [rejected, wrong aud]
Real-world example
No public incident has been reported where a named victim lost data specifically to MCP token mis-redemption. The risk is documented in:
- MCP specification, revision 2025-06-18 — introduced the requirement that MCP clients implement RFC 8707 Resource Indicators, and explicitly prohibited token passthrough. This revision is the one the ecosystem refers to when it says “resource indicators were made mandatory”.
- MCP specification, revision 2025-11-25 (the current authorization document) — tightens the language: “MCP clients MUST implement Resource Indicators for OAuth 2.0 as defined in RFC 8707”, “MCP servers MUST only accept tokens specifically intended for themselves”, “token passthrough is explicitly forbidden”.
- Commentary and guidance from Auth0, Descope, Scalekit, Den Delimarsky, Stytch, Aembit, Fluid Attacks, and Christian Schneider explaining the confused-deputy rationale.
Treat this page’s impact and prevention sections as research/theory as of 19 April 2026 for named exploitation — there is no public CVE or victim report yet. The specification change itself is a concrete, verifiable artefact.
Impact
- Privilege escalation across MCP servers. A token from a low-privilege server used to impersonate the user at a high-privilege one (e.g. a read-only search MCP escalating into a file-write MCP).
- Silent data exfiltration when a downstream API accepts forwarded tokens — the MCP server’s logs show a normal proxy call while the downstream sees direct user access.
- Bypassed rate limits and audits. Token passthrough skips the MCP server’s own instrumentation.
- Trust-boundary erosion across organisations. If two MCP servers share an authorization server, a compromise of the less-trusted one escalates across both.
Detection
- Inspect access tokens issued to MCP servers: if the
audclaim is missing, or is a wildcard, the issuer is out of compliance with the current spec. - In MCP server logs, alert on inbound tokens whose
auddoes not match the server identity. Reject them. - Outbound side: if an MCP server makes downstream API calls, ensure it uses its own credentials or a token-exchange flow, not the client’s token.
- Monitor authorization-server logs for token requests missing the
resourceparameter. - Pen-test: attempt to present a token issued for server A to server B; both current-spec servers should refuse.
Prevention
Token mis-redemption is primarily a spec-compliance problem — use an authorization server that honours RFC 8707 and MCP servers that validate aud. A policy proxy adds defence in depth by validating aud on every inbound request and refusing onward calls that would reuse an inbound token verbatim.
Example Intercept policy illustrating wire-level audience enforcement:
version: "1"
description: "Enforce audience binding on MCP traffic"
default: "allow"
tools:
"*":
rules:
- name: "require audience claim"
conditions:
- path: "auth.token.aud"
op: "eq"
value: "${server.identity}"
on_deny: "Token audience does not match this MCP server (RFC 8707 violation)"
- name: "reject passthrough of inbound token to upstream"
conditions:
- path: "auth.passthrough"
op: "eq"
value: false
on_deny: "Token passthrough is forbidden by MCP spec (2025-06-18 and later)"
The auth.token.aud and auth.passthrough paths are illustrative — confirm exact bindings against your Intercept version. Structure is valid; the specific paths are speculative.
Complementary controls:
- Use an authorization server that supports RFC 8707 (Keycloak, Auth0, Okta, Descope, WorkOS all have native or near-native support).
- Short token lifetimes; rotate and revoke aggressively.
- Separate authorization servers per trust tier — do not let a public MCP server share an issuer with an admin-plane MCP server.
- Where tokens must reach downstream services, use OAuth 2.0 Token Exchange (RFC 8693) rather than passthrough.
Sources
- Model Context Protocol, Authorization spec (2025-11-25) — https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization (accessed 19 April 2026)
- Model Context Protocol, Authorization spec (2025-06-18) — https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization (accessed 19 April 2026)
- IETF RFC 8707, “Resource Indicators for OAuth 2.0” — https://datatracker.ietf.org/doc/html/rfc8707 (accessed 19 April 2026)
- Auth0, “Model Context Protocol (MCP) Spec Updates from June 2025” — https://auth0.com/blog/mcp-specs-update-all-about-auth/ (accessed 19 April 2026)
- Den Delimarsky, “Update To MCP Authorization Spec - Resource Parameter (RFC 8707)” — https://den.dev/blog/mcp-authorization-resource/ (accessed 19 April 2026)
- Scalekit, “OAuth 2.0 resource indicators (RFC 8707) explained” — https://www.scalekit.com/blog/resource-indicators-for-oauth-2-0 (accessed 19 April 2026)
- Descope, “Diving Into the MCP Authorization Specification” — https://www.descope.com/blog/post/mcp-auth-spec (accessed 19 April 2026)
- dasroot.net, “The New MCP Authorization Specification — OAuth 2.1 and Resource Indicators”, April 2026 — https://dasroot.net/posts/2026/04/mcp-authorization-specification-oauth-2-1-resource-indicators/ (accessed 19 April 2026)
- “Unraveled Strands”, “MCP Version 2025-06-18 Changes: Confused No More!”, 23 June 2025 — https://unraveledstrands.com/2025/06/23/mcp-version-2025-06-18-changes-confused-no-more/ (accessed 19 April 2026)
- Kane.mx, “Technical Deconstruction of MCP Authorization: A Deep Dive into OAuth 2.1 and IETF RFC Specifications” — https://kane.mx/posts/2025/mcp-authorization-oauth-rfc-deep-dive/ (accessed 19 April 2026)
- ForgeCode, “MCP 2025-06-18 Spec Update: AI Security, Structured Output, and User Elicitation for LLMs” — https://forgecode.dev/blog/mcp-spec-updates/ (accessed 19 April 2026)
Related attacks
- MCPwn auth bypass (different auth failure mode in the same protocol)
- Tool poisoning in MCP definitions
Protect your agent in 30 seconds
Scans your MCP config and generates enforcement policies for every server.
npx -y @policylayer/intercept init