// AI threat desk · 1 Oct 2026
Home/CVE · Vulns & Patches
Vulns & PatchesHighMCPCVSS 7.5 (unattended providers), 6.5 (interactive provider)

MCP Python SDK OAuth Flaw Lets Malicious Servers Steal Access Tokens

The OAuth client implementation in the official MCP Python SDK has a flaw. A malicious MCP server can trick applications into sending client secrets, authorization codes and PKCE verifiers to an attacker-controlled endpoint. The flaw is fixed in versions 1.30.0 and 2.2.0. The advisory, issued Sep 28, reports no known exploitation, but defenders should upgrade quickly and check issuer settings.

Illustration: server racks and network cables, representing authentication infrastructure. Image source: created by owleval.com
File photo: Illustration: server racks and network cables, representing authentication infrastructure. Image source: created by owleval.com. Photo: U.S. Department of Agriculture / rawpixel (CC0)
Key takeaways
  • The OAuth client implementation in the official MCP Python SDK has a flaw. A malicious MCP server can make an application send its client secret, authorization code and PKCE verifier to an attacker, who can then obtain a validly scoped access token.
  • The flaw affects two version lines, 1.9.1 to 1.29.1 and 2.0.0 to 2.1.1. It carries a CVSS score of 7.5 (High) for unattended authorization flows and 6.5 for interactive flows that require manual login. As of Sep 29, no CVE number has been assigned.
  • The fix shipped in versions 1.30.0 and 2.2.0. Users of ClientCredentialsOAuthProvider or PrivateKeyJWTOAuthProvider must also set the issuer= parameter after upgrading to fully resolve the issue.
On this page

The Flaw Stems From the SDK Not Verifying the Authorization Server’s Identity

According to the security advisory published by the MCP project on GitHub, the OAuth client module of the MCP Python SDK (mcp.client.auth) fails to verify the issuer field in the authorization server metadata on certain discovery paths. It also does not bind stored or preconfigured client credentials to a specific authorization server.

The advisory states that a malicious or compromised MCP server can exploit this to redirect the client to a token endpoint of its choosing. This can be done by claiming to be the authorization server in the protected resource metadata, or by omitting that metadata altogether and instead impersonating the user’s real authorization server. Once successful, an attacker can obtain the client_secret, the authorization code and the PKCE code_verifier. If PrivateKeyJWTOAuthProvider is used, the attacker can also obtain a signed client assertion.

How Attackers Bypass Two Layers of Security Checks

Security firm Cycode explains in its report that the SDK’s normal identity discovery flow compares the issuer field in the authorization server metadata against the originally obtained URL. However, in the ‘legacy fallback path’, the SDK never obtains the original URL, so this check is never performed at all. An attacker only needs to have their server respond with a 404 to the discovery request. The SDK then falls back to the legacy path, requests login configuration directly from the attacker’s server, and accepts it without question.

Cycode also points out that the SDK’s second line of defense, ‘credential binding’, can likewise be bypassed. That check compares against the same issuer field that the attacker controls. The attacker simply fills that field with the name of the user’s real authorization server, and the check passes incorrectly. Because the login page itself is the genuine authorization server page, the user sees nothing unusual. The user only sees the MCP server ‘fail’ after authorization, while in reality the credentials have already been sent to the attacker.

Scope of Impact and Severity Scores

The advisory states that versions 1.9.1 to 1.29.1 lack the check on all discovery paths. In the 2.x series, versions 2.0.0 to 2.1.1 have the same issue when the server does not provide protected resource metadata (legacy fallback) or responds with 403 insufficient_scope. Affected providers include OAuthClientProvider, ClientCredentialsOAuthProvider, PrivateKeyJWTOAuthProvider, and the deprecated 1.x RFC7523OAuthClientProvider.

The flaw scores 7.5 (High) for the two unattended providers (machine-to-machine). It scores 6.5 for the interactive OAuthClientProvider scenario, which requires manual login initiation. As of Sep 29, neither the advisory nor the report have been assigned a CVE number. Both the advisory and Cycode state that no known cases of exploitation have been found, and no other sources have reported related attacks.

Patch Timeline and Remaining Gaps

The v1.30.0 release notes show that the issuer check was actually released on Sep 7 as a ‘behavior change’ rather than as a labeled security fix. The security advisory itself was issued on Sep 28, the same day Cycode published its research report. The advisory lists eight reporters in total, including Cycode’s researchers.

The advisory specifically warns that users of ClientCredentialsOAuthProvider or PrivateKeyJWTOAuthProvider cannot rely on upgrading alone. They must also pass the issuer= parameter to specify the intended authorization server. Otherwise, the client will still follow whatever server the MCP server designates. In version 1.30.0, omitting this parameter only triggers a deprecation warning that is hidden by default in Python and is easy to miss. The deprecated RFC7523OAuthClientProvider has no issuer option at all, and the official recommendation is to switch to one of the other two providers. This kind of OAuth-related supply chain risk belongs to the same threat trend covered in our earlier report on AI agent supply chain security.

What to do now

  1. Upgrade the MCP Python SDK to version 1.30.0 or later on the 1.x line, or 2.2.0 or later on the 2.x line
  2. If using ClientCredentialsOAuthProvider or PrivateKeyJWTOAuthProvider, pass the issuer= parameter to specify the authorization server after upgrading
  3. Clear all stored OAuth client registration records once, since old records were not bound to a specific authorization server
  4. If you suspect a client has connected to an untrusted MCP server, rotate that client’s secret and revoke related tokens at the authorization server
  5. Until you can upgrade, only connect to trusted MCP servers and avoid using this SDK with unknown or third-party servers

FAQ

What is PKCE, and why does this flaw defeat it?

PKCE (Proof Key for Code Exchange) is a one-time verifier generated by the client at the start of the login flow. It proves that the client exchanging the authorization code is the same one that started the flow, and it is meant to prevent a stolen authorization code from being reused. According to Cycode’s report, this flaw causes the PKCE verifier to be sent to the attacker along with the authorization code and client secret, defeating that protection.

Is MCP Python SDK version 1.29 affected?

Yes. According to the GitHub security advisory, versions 1.9.1 to 1.29.1 lack issuer verification on all discovery paths and are within the affected range. Users should upgrade to version 1.30.0 as soon as possible.

Has this flaw been actively exploited?

According to the GitHub security advisory and Cycode’s report, neither has found any known cases of exploitation. No other sources have reported related attacks at this time.

Is upgrading the SDK version alone enough to be secure?

Not necessarily. The security advisory states that users of ClientCredentialsOAuthProvider or PrivateKeyJWTOAuthProvider must also pass the issuer= parameter to specify their authorization server after upgrading. Otherwise, the protection is incomplete.

Has this flaw been assigned a CVE number?

According to reports, as of Sep 29, 2026, the flaw has not been assigned a CVE number.

Sources

  1. OAuth client could send credentials to an authorization server chosen by the MCP server, GitHub Security Advisory GHSA-qx49-fqc8-xw99Primary
  2. v1.30.0 release notes, modelcontextprotocol/python-sdkPrimary
  3. Cycode Uncovers Account Takeover in MCP Python SDK, Cycode blog
Explore with AI