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.
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.
- 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.
- 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.
- 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
ApiClientclass.
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.descriptionandauth.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
audvalue 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:
- A CVSS 10.0 bug let one user's Terraform token serve another user's request (CVE-2026-16498, HashiCorp bulletin HCSEC-2026-23, July 2026)
- Duende OAuth token management mixes tokens across requests (CVE-2025-26620, February 2025)
- Okta Java SDK race condition crosses responses between requests (CVE-2025-67505, December 2025)
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.
- HashiCorp HCSEC-2026-23: multiple vulnerabilities impacting Terraform MCP Server
- NVD: CVE-2026-16498
- NVD: CVE-2025-26620 and the Duende advisory GHSA-qxj7-2x7w-3mpp
- NVD: CVE-2025-67505 and the Okta advisory GHSA-j5gq-897m-2rff
- Model Context Protocol: security best practices
- Model Context Protocol specification
- HCP Terraform: audit trails API
- RFC 8693: OAuth 2.0 Token Exchange
- The Hacker News: HashiCorp, Veeam, Django patch CVSS 10.0 flaws
Related identity CVEs and breaches
Related on Start with Identity
- CVEJFrog Artifactory checks a token's signature and issuer but not its scope
Self-hosted Artifactory before 7.133.11 validated access token signatures and issuers without enforcing scope, so a low-privilege token could perform admin acti
- CVEAD FS elevation of privilege exploited as a zero-day
A low-privileged local user on an AD FS server could become administrator on the box that holds the federation token-signing keys. Microsoft saw exploitation be
- CVEFreeIPA anonymous LDAP write plants a Kerberos principal in the admins group
FreeIPA's self-managed OTP token ACI let an anonymous LDAP client create a token entry with extra attributes, which combined with a 389 Directory Server ACI fla
- VendorAserto
strong
- VendorAuthZed
top_tier
- Comparisonauthzed-vs-openfga
Both are Apache 2.0 Zanzibar-style ReBAC engines. SpiceDB (AuthZed) has token-based point-in-time consistency and capacity-priced managed tiers; OpenFGA is a CN