Skip to content
Start with Identity
SWI-T013 · Authorization

Cross-tenant token confusion

A broker sitting between users and a shared backend fails to keep sessions apart, so a token supplied by one caller gets used to serve a different caller's later request, with no attack step beyond timing.

EmergingHard to detect
First observed: 2025

How it works

A broker sits between a set of callers and a privileged backend API. It might be an MCP (Model Context Protocol) server that lets agents call Terraform, GitHub or a cloud API; an API gateway that injects credentials; or an SDK inside a multi-tenant web application that caches tokens for outbound calls. Each caller supplies, or is mapped to, its own credential and expects the broker to use that credential only for that caller's requests. The broker keeps that mapping in some piece of state: a session object, a cache keyed by session ID, a token store keyed by client and scope, or a shared HTTP client object.

Token confusion happens when that key is missing, shared or racy, so the broker looks up the wrong entry. Three concrete versions are on record.

  1. No unique session key. HashiCorp's Terraform MCP Server (CVE-2026-16498, CVSS 10.0, fixed in 1.1.0) ran in streamable-HTTP stateless mode on an MCP library that did not assign unique session identifiers. The server's credential cache relied on those identifiers to tell users apart, so one user's Terraform token could be used to execute tool calls on behalf of subsequent users, regardless of the token they supplied. The same HashiCorp bulletin, HCSEC-2026-23, covered a companion flaw in stateful mode (CVE-2026-16496) where anyone who obtained another user's MCP session ID had their tool calls executed with that user's Terraform credentials.
  2. A race in a token cache. Duende's .NET AccessTokenManagement library (CVE-2025-26620) had a race in its client credentials flow: concurrent requests with different protocol parameters could receive access tokens obtained with the wrong scope, resource indicator, or other parameters.
  3. Shared mutable state in an SDK client. Okta's Java Management SDK (CVE-2025-67505, versions 11.0.0 through 20.0.0, fixed in 20.0.1) could let a status code or response header from one request influence another concurrent request's response when callers shared the ApiClient class.

There is no exploit step in the conventional sense for the first two. A normal concurrent workload against the broken broker produces the confusion on its own, and the backend API sees a token it recognizes on a request that looks legitimate, because it is a real token, just the wrong one. Where session IDs are guessable or leak, as in the stateful Terraform case, an attacker can also induce the mix-up deliberately.

Why it works

A broker between an agent and a privileged API is functionally a credential store, and its entire value depends on never confusing whose credential belongs to whose request. The control assumption that fails is that "stateless" and "must not mix up two callers" are compatible by default. They are not: statelessness removes the persistent session object that would normally anchor a credential to a caller, so unless the broker makes caller identity an explicit, per-request input rather than an artifact of shared state, two concurrent requests can end up sharing a credential neither of them supplied.

The second failed assumption is that the session identifier is an identity. The MCP security best practices say it plainly: MCP servers must not use sessions for authentication, must use secure non-deterministic session IDs, and should bind session IDs to user-specific information, using a key such as <user_id>:<session_id>, so that a guessed or reused session ID cannot impersonate another user. The Terraform bugs are what happens when the session ID is the only key.

The third is that bearer tokens are safe to cache by anything other than their owner. A bearer token carries no proof of who is presenting it, so the backend has no way to notice the mix-up. Sender-constrained tokens would have made a swapped token fail.

How to detect it

  • Backend audit trails against broker logs. In HCP Terraform, the organization audit trail records each event's auth.accessor_id, auth.description and auth.type, for the past 14 days. Correlate those against the broker's own request log: an action attributed to user A's token that the broker logged as user B's request is the confusion, seen from both sides.
  • Session identifiers in broker logs. Requests from different authenticated callers sharing a session ID, or requests with no session ID at all in a mode that should assign one.
  • Actions on resources with no prior relationship. API calls under one caller's credential against workspaces, repositories or accounts that caller has never touched before, in a short window after a different caller's activity.
  • Scope or audience mismatches. For the Duende class, access tokens presented downstream with a scope or aud value the calling component never requested. Resource servers that log the token's scope and audience on rejection will show this.
  • Load test assertions. Concurrency tests that assert user A never receives user B's sub, scope or response. This is the only detection that runs before production.

Be honest about the limits: this is a broker implementation bug, not an adversary campaign, so there is no attacker behavior pattern to alert on. Detection depends on the broker emitting caller identity and session IDs, and on correlating broker-side logs with backend-side action logs, which most deployments do not do by default. Absent that correlation, the confusion is invisible from either log alone. The backend sees a valid token; the broker sees a valid request. Many incidents of this class will only ever surface as "a user saw something that was not theirs."

How to stop it

  • Patch first. Upgrade terraform-mcp-server to 1.1.0 or later, Duende.AccessTokenManagement to a fixed release, and the Okta Java Management SDK to 20.0.1 or later. Check every MCP server and SDK in front of a privileged API for disclosed session-handling flaws; this is supply chain risk in the non-human identity layer.
  • Key every credential lookup on caller identity. Bind each request to an explicit authenticated identity, and key caches as identity plus session plus scope, never session alone. Do not store tokens in a singleton without a per-user key.
  • Do not pass caller tokens through. The MCP authorization specification forbids token passthrough, where a server forwards tokens that were not issued to it. Prefer token exchange so the broker obtains a downstream token scoped to the specific caller and audience. See MCP authorization.
  • Constrain tokens to the sender. DPoP or mTLS make a token useless on the wrong client, and resource indicators narrow where it can be used.
  • Scope brokered tokens tightly so that even a mix-up cannot cross an environment or tenant boundary.
  • Log and reconcile broker sessions against backend actions so a confusion event is detectable after the fact even without a real-time alert.

Seen in the wild

No exploited incident of this technique is recorded in the SWI Identity Breach Database, and none of its 123 records lists it. The cases on file are disclosed vulnerabilities, not attributed attacks:

The Identity Breach Report 2026 is relevant context: non-human identities were the abused identity in 32% of 2025-2026 breaches (16 of 50), and none of the four AI-related records involved an agent as the abused identity. Brokers like MCP servers are where that could change.

Sources

No ATT&CK technique fits. The closest candidates, T1550.001 (Use Alternate Authentication Material: Application Access Token) and T1528 (Steal Application Access Token), both describe an adversary deliberately stealing or replaying a token. Here the broker itself applies the wrong token, often with no adversary involved, and the misuse is a side effect of a concurrency or session-keying bug. Rather than force a mapping, this brief cites no attack_mitre ID.

Related identity CVEs and breaches

Last reviewed By SWI Community TeamSuggest a correctionHow we research
Seeing this technique used differently, or have a detection rule that works better? Email community@startwithidentity.com. See all briefs in the technique catalog, or volunteer as a CVE Analyst.
Mapped to MITRE ATT&CK where a technique ID exists. Independent, community-driven analysis, not a substitute for the ATT&CK knowledge base. See the disclaimer.