A Hostile MCP Server Could Steer OAuth Secrets Away From the Official TypeScript SDK’s Clients
CVE-2026-104850, published on October 6, 2026, is a High-severity flaw in the OAuth client support of the official Model Context Protocol TypeScript SDK. A malicious MCP server could name its own authorization server and receive stored refresh tokens or client secrets. Fixes shipped in @modelcontextprotocol/sdk 1.31.0 and @modelcontextprotocol/client 2.2.0, and some setups also need configuration changes.
The official TypeScript SDK for the Model Context Protocol (MCP) let a connected MCP server decide which authorization server received a client’s OAuth credentials. That flaw is now on record as CVE-2026-104850. GitHub, acting as CNA, published the record on October 6, 2026 at 16:08 UTC, and NVD listed it about an hour later with the status Awaiting Analysis. The CNA scores it 7.5 (High) under CVSS 3.1, with network attack vector, low complexity, no privileges, no user interaction, and high confidentiality impact. The weaknesses listed are CWE-345, insufficient verification of data authenticity, and CWE-522, insufficiently protected credentials.
The fixes are not new. @modelcontextprotocol/sdk 1.31.0 and @modelcontextprotocol/client 2.2.0 reached npm on September 28. The project’s GitHub security advisory, GHSA-6qxp-vccf-f47h, followed on September 30. The CVE is the new hook, and the package’s reach is what makes it worth a look: npm counted about 76.2 million downloads of @modelcontextprotocol/sdk in the week of September 28 to October 4.
Credentials that were not tied to an issuer
MCP clients that talk to a server over HTTP can authenticate with OAuth. The advisory says that in affected versions, stored and pre-provisioned credentials “were not tied to the authorization server they belong to.” A malicious or compromised MCP server could name its own authorization server in its protected resource metadata. With no user interaction, the client would then send that server the refresh_token and client_secret saved from an earlier sign-in. On clients using a bundled non-interactive provider, it would send the configured client_secret or signed assertion instead.
The result is credential theft across trust boundaries. An application that holds valid credentials for a legitimate authorization server, and also connects to an MCP server it does not fully control, could hand those credentials to whoever runs that server.
Which deployments are exposed
The advisory sets out two conditions. An application is affected if it uses the SDK’s OAuth client over HTTP, through an authProvider on a transport, the withOAuth() middleware, or direct calls to auth() or fetchToken(), and it may connect to an MCP server it does not fully trust while holding credentials for a legitimate authorization server.
The affected range for the 1.x line is @modelcontextprotocol/sdk 1.12.0 through 1.30.1. Version 1.12.0 reached npm in May 2025. On 2.x, @modelcontextprotocol/client 2.0.0 through 2.1.0 is affected only in specific cases: bundled providers without expectedIssuer, credentials stored or supplied without an issuer, direct fetchToken() calls, and providers that read storage back through the SDK’s token or client-information schemas. The bundled providers named in the record are ClientCredentialsProvider, PrivateKeyJwtProvider, StaticPrivateKeyJwtProvider, and, on 2.x, CrossAppAccessProvider. MCP servers built with the SDK are not affected, and neither are stdio clients.
Why a version bump is only half the job
After the fix, the client records the authorization server as the issuer on saved credentials and will not send them to a different one. The user either signs in again or the call throws. For several common setups, the advisory says upgrading is “not enough”:
- Bundled providers need an explicit
expectedIssuer. Without it, they still use whichever authorization server the MCP server names. - Credentials saved before the upgrade carry no issuer. That covers everything 1.x stored before 1.31.0, whether in files, keychains, or databases. These still go to whichever authorization server is named at first use, so they need an issuer added, or they should be cleared to force a fresh sign-in.
- Custom
OAuthClientProviderimplementations must persist exactly whatsaveTokens()andsaveClientInformation()receive, including the issuer, and pre-registered credentials should return an issuer fromclientInformation().
The advisory also lists what the fix does not cover. A new interactive sign-in still goes to the authorization server the MCP server names, so users should complete sign-ins only for servers they trust. Direct calls to refreshAuthorization() and exchangeAuthorization() are outside the fix, as is 2.x running with skipIssuerMetadataValidation: true.
What teams should do now
The minimum is @modelcontextprotocol/sdk 1.31.0 or @modelcontextprotocol/client 2.2.0, plus @modelcontextprotocol/core 2.2.0 if it is imported directly. On npm, the current releases are 1.32.1 and 2.3.1. If an affected client may have connected to an untrusted MCP server, the advisory says to rotate its client secret or signing key and revoke its tokens. Teams that cannot upgrade yet on 1.x should connect OAuth-enabled clients only to trusted MCP servers. Versions 2.0.0 and 2.1.0 already accept expectedIssuer as a workaround.
The GitHub advisory credits seven reporters. The flaw fits a wider pattern for agent tooling: as clients connect to more third-party MCP servers, the server itself becomes a party that may try to redirect where the client’s trust goes.
- #Cybersecurity
- #Model Context Protocol
- #OAuth
- #CVE
- #AI Agents
Author
Raj M
Contributor
AI Systems Architect is a seasoned technology leader with over 15 years of experience in the IT industry working with Fortune 500 companies. With a solid foundation in multi-agent systems, open-source LLM infrastructure, and enterprise deployment, he excels at building scalable production-grade AI platforms.