@MODELCONTEXTPROTOCOL/SDK · CVE-2026-104850 · AI agents & MCP
FIX → 1.31.0 · 2.2.0
The MCP TypeScript SDK's OAuth client let the MCP server choose which authorization server receives the client's saved refresh tokens and client secrets. A malicious or compromised MCP server can thus collect those credentials without any user interaction.
first public Sep 30, 2026 · 3 sources
Could this affect your app?
Free first check from your website. Connect your repo for the full answer.
Applications that use the SDK's OAuth client over HTTP and may connect to MCP servers that are not fully trusted while holding credentials for a legitimate authorization server. MCP servers built with the SDK and stdio clients are not affected. Upgrading is not enough on its own for bundled providers without expectedIssuer and for credentials stored without issuer.
Not affected if mcp-servers-only, stdio-clients, trusted-servers-only
Who cares mcp, node.js, oauth, typescript
npm ls @modelcontextprotocol/sdk @modelcontextprotocol/clientauthProvider on a transport, withOAuth(), or direct calls to auth() or In affected versions, the SDK's OAuth client let the MCP server decide which authorization server received the client's OAuth credentials. Credentials were not tied to the authorization server they belong to.
A malicious or compromised MCP server could name its own authorization server. With no user interaction, the client would send it:
refresh_token and client_secret stored from an earlier sign-inclient_secret or signed assertion configured on a bundled providerYes, if both of these hold:
authProvider on a transportwithOAuth() middlewareauth() or fetchToken()Affected versions:
Check it with your coding agent
It reads this page and tells you if your code is affected.
Are you affected?
Ask from here. InfraStack checks the affected versions against your stack and answers in your inbox.
InfraStack checks the affected versions against your stack and answers in Slack, with the evidence and the fix.
fetchToken()ClientCredentialsProvider, PrivateKeyJwtProvider, StaticPrivateKeyJwtProvider, CrossAppAccessProvider) lack expectedIssuerUpgrade to 1.31.0 · 2.2.0
@modelcontextprotocol/sdk: 1.31.0 or later (affected 1.12.0 through 1.30.1)@modelcontextprotocol/client: 2.2.0 or later (affected 2.0.0 through 2.1.0), and @modelcontextprotocol/core 2.2.0 or later if imported directlyexpectedIssuer; credentials saved without issuer need it added or need clearing@modelcontextprotocol/sdk 1.12.0 through 1.30.1@modelcontextprotocol/client 2.0.0 through 2.1.0, only for:
expectedIssuerissuerfetchToken()OAuthTokensSchema or OAuthClientInformationSchemaNot affected:
Upgrade to:
@modelcontextprotocol/sdk 1.31.0 or later@modelcontextprotocol/client 2.2.0 or later, and @modelcontextprotocol/core 2.2.0 or later if you import it directlyThe client now records the authorization server as issuer on saved credentials and does not send them to a different one. The user signs in again, or the call throws.
In the following cases, upgrading to the patched version is not enough. You also need to make a change:
ClientCredentialsProvider, PrivateKeyJwtProvider, StaticPrivateKeyJwtProvider, CrossAppAccessProvider): pass expectedIssuer, for example expectedIssuer: 'https://auth.example.com'. Without it they still use whichever authorization server the MCP server names.issuer: tokens and client information your OAuthClientProvider persisted (file, keychain, database) before upgrading, including everything 1.x saved before 1.31.0. They still go to whichever authorization server is named at first use. Add issuer to them, or clear them so users sign in again.OAuthClientProvider: save exactly what saveTokens() and saveClientInformation() are given, including issuer. For pre-registered credentials, include issuer in what clientInformation() returns.Not covered by this fix:
refreshAuthorization() and exchangeAuthorization() called directlyskipIssuerMetadataValidation: trueIf an affected client may have connected to an untrusted MCP server, rotate its client secret or signing key and revoke its tokens.
If you cannot upgrade yet, connect OAuth clients only to MCP servers you trust. 2.0.0 and 2.1.0 already accept expectedIssuer.
This page as .md · .json · CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
GitHub Advisory Database, CC-BY 4.0 · NVD data is provided by NIST and is public domain. Posts quoted belong to their authors.