
Applications built on the official MCP Python SDK can now defend against a flaw that let a malicious server steal the OAuth credentials used to log in to a real service. The SDK’s maintainers shipped the fix in versions 1.30.0 and 2.2.0, and upgrading closes the path that exposed the client secret, the authorization code, and the PKCE proof key to a token endpoint controlled by an attacker.
The Model Context Protocol (MCP) is an open standard for connecting AI applications to outside tools and data, and the affected package is its official Python SDK for building MCP servers and clients. The flaw lives in how the SDK handles the OAuth login step when an MCP client connects to a server over HTTP. The SDK asks the server where its login service, the authorization server, can be reached, and on affected versions it did not check that the answer pointed to the service the credentials actually belong to. A malicious server could redirect the client to an attacker-controlled login service and receive the secret, the authorization code, and the PKCE proof key in place of the real provider.
What an attacker can do with the stolen credentials
The stolen client secret is long-lived, so it keeps working until it is rotated. With the secret, the authorization code, and the PKCE proof key, the attacker can request a valid access token from the real login service. The PKCE proof key is supposed to be a one-time value that prevents a stolen authorization code from being replayed, so handing it over defeats that protection as well. The resulting token carries whatever permissions the application was granted, which is the full set of scopes the developer assigned to the MCP client.
The flaw is rated high at a CVSS score of 7.5 for the two OAuth providers that run without a person present, and 6.5 for the interactive provider where someone has to start the sign-in. With the interactive provider, the page they approve is the genuine login page, so nothing looks wrong to the user. No CVE had been assigned as of the advisory publication.
Who is affected
An application is affected if it uses the SDK as an MCP client over HTTP with one of the OAuth providers OAuthClientProvider, ClientCredentialsOAuthProvider, PrivateKeyJWTOAuthProvider, or the deprecated 1.x RFC7523OAuthClientProvider, and it can connect to a server it does not fully control while holding credentials for a real login service. MCP servers built with the SDK, local stdio clients, and clients that attach their own tokens are not affected.
- 1.x line: versions 1.9.1 through 1.29.1 are affected, fixed in 1.30.0
- 2.x line: versions 2.0.0 through 2.1.1 are affected, fixed in 2.2.0
What the fix does and what still requires action
In the fixed versions, the client works out which login service it expects before fetching any details and refuses any answer that names a different one. Upgrading is not the whole fix for two of the providers. Applications using ClientCredentialsOAuthProvider or PrivateKeyJWTOAuthProvider also have to pass an issuer parameter that names the login service those credentials belong to. Without it, those providers still follow whichever server the MCP server points them at, even on the patched version. On 1.30.0, the warning about this is a standard Python deprecation warning, which Python hides by default and is easy to miss. The deprecated RFC7523OAuthClientProvider has no issuer option at all, so applications on it need to move to one of the other two providers.
After upgrading, stored OAuth client registrations should be cleared once, because older ones are not tied to a login service and stay that way. If a client may already have connected to an untrusted server, the client secret should be rotated and existing tokens should be revoked at the login service. On older versions, there is no workaround other than connecting only to MCP servers that are fully trusted.
How the flaw was disclosed
The issuer checks shipped in the 1.30.0 and 2.2.0 release notes on September 7, listed under behavior changes rather than as a security fix. The advisory followed on September 28. The security firm that demonstrated the credential exchange in a test published its writeup the same day. The advisory credits eight reporters. Neither the advisory nor the firm’s writeup reports any attacks using the flaw, and none has been reported elsewhere.
FAQ
What is the MCP Python SDK vulnerability?
The official MCP Python SDK had a flaw in its OAuth handling that let a malicious MCP server trick a client into sending its client secret, authorization code, and PKCE proof key to an attacker-controlled token endpoint. The fix is in versions 1.30.0 and 2.2.0.
Which SDK versions are affected?
Versions 1.9.1 through 1.29.1 on the 1.x line and 2.0.0 through 2.1.1 on the 2.x line are affected. Versions 1.30.0 and 2.2.0 contain the fix.
What should developers do beyond upgrading?
Applications using ClientCredentialsOAuthProvider or PrivateKeyJWTOAuthProvider must also pass an issuer parameter naming the login service those credentials belong to, otherwise they still follow whatever server the MCP server points them at. Stored OAuth client registrations should be cleared, and if a client may have connected to an untrusted server, the client secret should be rotated and tokens revoked at the login service.
This article summarizes reporting from thehackernews.com.
