MCP TypeScript SDK let a malicious server pick where OAuth refresh tokens and secrets were sent
An advisory published on 6 October, GHSA-6qxp-vccf-f47h (CVE-2026-104850, high), describes a flaw in the OAuth client of the Model Context Protocol TypeScript SDK: credentials were not tied to the authorization server they belong to, so the MCP server decided where they were sent.
The attack. A malicious or compromised MCP server could name its own authorization server. With no user interaction, the client would send it the refresh_token and client_secret stored from an earlier sign-in, or the client_secret or signed assertion configured on a bundled provider.
Who is affected. Applications that use the SDK's OAuth client over HTTP, through an authProvider on a transport, the withOAuth() middleware, or direct calls to auth() or fetchToken(), and that may connect to an MCP server they do not fully trust while holding credentials for a legitimate authorization server.
@modelcontextprotocol/sdk1.12.0 through 1.30.1;@modelcontextprotocol/client2.0.0 through 2.1.0, in specific cases listed in the advisory.

MCP servers built with the SDK and stdio clients are not affected.
The fix. Upgrade to @modelcontextprotocol/sdk 1.31.0, or @modelcontextprotocol/client 2.2.0 (and @modelcontextprotocol/core 2.2.0 if imported directly). The client now records the authorization server as issuer on saved credentials and refuses to send them elsewhere.
When upgrading is not enough. The advisory lists three cases that need a code or data change:
- Bundled providers (
ClientCredentialsProvider,PrivateKeyJwtProvider,StaticPrivateKeyJwtProvider,CrossAppAccessProvider) must be givenexpectedIssuer; without it they still use whatever authorization server the MCP server names. - Credentials saved without
issuer, including everything 1.x stored before 1.31.0, still go to whichever server is named at first use: addissuerto them, or clear them so users sign in again. - Custom
OAuthClientProviderimplementations must store exactly whatsaveTokens()andsaveClientInformation()receive, includingissuer.
The fix does not cover a new interactive sign-in, which still goes to the server the MCP server names, direct calls to refreshAuthorization() and exchangeAuthorization(), or 2.x with skipIssuerMetadataValidation: true. The advisory also advises rotating credentials if an affected client may have connected to an untrusted MCP server.