MCP TypeScript SDK CVE-2026-111771
MEDIUMAttack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
AccessObtain valid token for another service
-
DeliveryIdentify MCP server sharing authz server
-
ExploitReplay token to requireBearerAuth endpoint
-
ExecutionAudience check absent, token accepted
-
ImpactAccess unauthorized MCP tools and data
Vulnerability Assessment
| Weakness |
CWE
OWASP Top 10:2025
A01:2025 - Broken Access Control
ASVS 5.0
V8 - Authorization Authorization logic validation
MITRE ATT&CK
1 technique across 1 tactic: Privilege Escalation The technique list with ATT&CK links and the kill-chain view is part of the Basic plan and up. |
| Exploitation Conditions | Exploitation requires a specific, documented combination: (1) the MCP HTTP server uses requireBearerAuth() or verifyBearerToken() from an affected SDK version (@modelcontextprotocol/sdk 1.6.0-1.31.0, @modelcontextprotocol/server 2.0.0-2.2.0, @modelcontextprotocol/express 2.0.0-2.0.1, or @modelcontextprotocol/server-legacy 2.0.0-2.3.0); (2) the same authorization server issues valid tokens for OTHER services besides this MCP server; and (3) the application's own verifyAccessToken() does not independently validate the token's 'aud' (audience) claim. Limiting factors that reduce real-world exposure: the attacker must already hold a valid token issued by that shared authorization server for a different service (PR:L), so this is not an unauthenticated bypass; environments using a dedicated single-audience authorization server, or whose verifyAccessToken() already checks 'aud', are not exploitable. Critically, the patched versions ship the 'expectedResource' audience check OFF by default - remediation requires both setting expectedResource on requireBearerAuth() and returning the token audience as AuthInfo.resource from verifyAccessToken(); upgrading alone changes nothing. |
| Impact | This is a moderate-severity authorization flaw (CWE-863, missing token audience validation) rated CVSS 6.8 with vector AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N. The signals are internally consistent and point to a real-but-conditional risk rather than a drop-everything emergency. The network vector (AV:N) and high confidentiality/integrity impact (C:H/I:H) are offset by two dampening metrics: AC:H reflects that exploitation depends on a specific deployment topology (one authorization server issuing tokens for multiple services AND the application not checking 'aud' itself), and PR:L reflects that the attacker must already possess a valid token legitimately issued for some other service by that shared authorization server - this is a confused-deputy/token-reuse condition, not an anonymous bypass. No EPSS score, no CISA KEV listing, and no public exploit were provided in the intelligence, so the exploitation status is 'no public exploit identified at time of analysis'; there is no evidence of active exploitation. The real priority is driven by the sensitivity of the data behind affected MCP servers and by how common the multi-service shared-authorization-server pattern is in a given environment, not by raw score. Note one nuance to verify: the patch is off by default (opt-in via 'expectedResource'), so merely upgrading does NOT remediate - this materially affects real-world residual risk and should be weighted in prioritization. |
| Exploit ScenarioDerived | An organization runs several services (e.g., an MCP server and an unrelated API) that all accept bearer tokens from one shared OAuth authorization server, and the MCP server's verifyAccessToken() does not check the token's audience. An attacker who legitimately obtains a token scoped for the other, lower-value service replays that same token against the MCP server, which accepts it and grants access to MCP tools and data it was never authorized for. No public exploit code was identified; the attack is a straightforward token replay requiring no special tooling once a valid cross-service token is held. |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – Oct 20, 2026
Bearer-token authorization bypass in the Model Context Protocol TypeScript SDK packages lets a token minted for a different service be accepted by an MCP HTTP server built on requireBearerAuth() or verifyBearerToken(), giving the token holder the identity, scopes and tool access of an authenticated MCP client. Affected are @modelcontextprotocol/sdk 1.6.0-1.31.0, @modelcontextprotocol/server 2.0.0-2.2.0, @modelcontextprotocol/express 2.0.0-2.0.1 and @modelcontextprotocol/server-legacy 2.0.0-2.3.0, but only deployments whose authorization server also issues tokens for other services and whose verifyAccessToken() does not itself check the 'aud' claim. The flaw is authenticated (CVSS 6.8, AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N) since the attacker must already hold a valid token from that shared authorization server; no public exploit code or confirmed active exploitation was identified at time of analysis, and note that upgrading alone does not remediate - the new expectedResource audience check ships disabled by default.
RemediationAI
Vendor-released patch: @modelcontextprotocol/sdk 1.32.0, @modelcontextprotocol/server 2.3.0, @modelcontextprotocol/express 2.0.2 and @modelcontextprotocol/server-legacy 2.3.1, with the upstream fix visible in commits 40f8f4e229d963cd7fd2890bda2aeebe7005299a, 5a0724d14cf34a27a3b070224d2996cdd611df9f and 5a1867390b91b8836f49af76c45427279f513325 and documented at https://github.com/modelcontextprotocol/typescript-sdk/security/advisories/GHSA-rvq5-wwqv-78pq. Upgrading is necessary but not sufficient: the new expectedResource option is off by default, so you must also pass the audience your authorization server stamps into tokens for this server - requireBearerAuth({ verifier, expectedResource: new URL('https://mcp.example.com/mcp') }) - and return that audience from verifyAccessToken() as AuthInfo.resource, itself a URL, sourced from the JWT 'aud' claim or the introspection 'aud' field; applying only the first change causes every request to return 401, so make both changes together and verify with a token issued for another service, which should now receive 401 invalid_token. Express users must additionally upgrade @modelcontextprotocol/express to 2.0.2, since 2.0.1 silently drops expectedResource and its options type rejects it at compile time. If you cannot upgrade yet, implement the equivalent control in application code by rejecting inside verifyAccessToken() any token whose 'aud' does not include your server's URL - this closes the issue on every affected version with no dependency change; the trade-off is that the check lives in your verifier rather than the middleware, so it must be duplicated in each MCP server and kept in sync with the resource identifiers your authorization server actually issues. Environments where the authorization server is dedicated to a single audience, or where 'aud' is already validated, can treat this as informational but should still plan the upgrade to avoid future regressions.
Affected Packages
Source: OSV (Open Source Vulnerabilities)
Affects your stack
Affects 4 packages in npm
Checking this CVE against your own stacks and servers is part of the Basic plan and up.
Technical ContextAI · show details
The MCP TypeScript SDK implements OAuth 2.0 bearer-token protection (RFC 6750) for streamable HTTP servers, delegating token validation to an application-supplied OAuthTokenVerifier whose verifyAccessToken() returns AuthInfo. Because AuthInfo carried no field for the token's intended audience and requireBearerAuth()/verifyBearerToken() had no expectedResource concept, the middleware could only check token validity, expiry and scopes - never the JWT 'aud' claim or the introspection response's 'aud' field that binds a token to a specific resource server (the RFC 8707 resource-indicator model). This is CWE-863 (Incorrect Authorization): a classic cross-service or 'confused deputy' audience-confusion pattern where a multi-tenant authorization server issuing tokens for several relying parties is trusted implicitly by every one of them. The upstream commits add an optional expectedResource option on a new VerifyBearerTokenOptions type (extending the unchanged BearerAuthOptions), compared as a string against AuthInfo.resource while ignoring a fragment and one trailing slash, and enforced through the Express requireBearerAuth() pass-through in @modelcontextprotocol/express 2.0.2 - 2.0.1 does not forward the option, so Express deployments must upgrade that package too. The corresponding CPE entries are the four npm packages pkg:npm/@modelcontextprotocol_sdk, _server, _express and _server-legacy.
Know when the next one hits your stack
- Watch products and get an email when something new is published
- Check this CVE against your own stack and servers
- Exploit and PoC references, threat intelligence from 22 sources
No credit card · 7-day full trial
Severity by source
AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N
AV:N (network bearer auth); AC:H because it needs a shared multi-service authz server and no app-side aud check; PR:L because the attacker needs a valid token for another service; C:H/I:H for unauthorized MCP access, A:N.
Primary rating from GitHub Advisory.
CVSS VectorGitHub Advisory
DescriptionGitHub Advisory
Summary
In affected versions, the SDK's server-side bearer authentication had no way to check that a token was issued for your server (its audience). Where one authorization server issues tokens for several services, a valid token for another service was also accepted by your MCP server.
Am I affected?
Yes, if your HTTP server uses requireBearerAuth() or verifyBearerToken(), its authorization server also issues tokens for other services, and your verifyAccessToken() does not check the token's audience (aud) itself.
Affected versions:
@modelcontextprotocol/sdk1.6.0 through 1.31.0@modelcontextprotocol/server2.0.0 through 2.2.0@modelcontextprotocol/express2.0.0 through 2.0.1@modelcontextprotocol/server-legacy2.0.0 through 2.3.0
Fix
Upgrade to:
- 1.x:
@modelcontextprotocol/sdk1.32.0 or later - 2.x:
@modelcontextprotocol/server2.3.0 or later, together with@modelcontextprotocol/express2.0.2 or later if you use it @modelcontextprotocol/server-legacy2.3.1 or later
Upgrading alone changes nothing. The patched versions add an expectedResource setting that is off by default. To turn the check on, make both of these changes together:
- Pass the audience your authorization server puts in tokens for your server:
requireBearerAuth({ verifier, expectedResource: new URL('https://mcp.example.com/mcp') }). - Return the token's audience from
verifyAccessToken()asAuthInfo.resource, also aURL.
A token for another service then gets 401. With only the first change, every request gets 401.
If you cannot upgrade yet, reject any token whose aud does not include your server inside verifyAccessToken(). That closes the issue on every version.
Blast Radius
ecosystem impact- 1,417 npm packages depend on @modelcontextprotocol/server (1,063 direct, 361 indirect)
Ecosystem-wide dependent count for version 2.0.0.
Threat Intelligence Overview
How this decision was reached
The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.
What every action level means
SSVC AssessmentENISA
Priority Score
Attack Technique
Authentication bypass attacks exploit flaws in the verification mechanisms that control access to systems and applications.
GHSA-rvq5-wwqv-78pq
NVD
CVE.org
Exploit-DB