The Official MCP Python SDK Leaked OAuth Secrets to Rogue Servers
A high-severity flaw in the official MCP Python SDK let a malicious server redirect an OAuth login and capture the client secret, authorization code, and PKCE proof key. Versions 1.9.1 through 2.1.1 are affected and fixes shipped in 1.30.0 and 2.2.0. Local stdio connections are unaffected, but clients that connected over HTTP to untrusted servers should rotate their secrets.
On this page
What the flaw leaked, and to whom
The Model Context Protocol's official Python SDK ships the client code many agents use to sign in to remote services. According to a security advisory published on 28 September, 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 did not consistently validate where an authorization server actually lived before sending credentials there.
The failure mode is simple once stated. An MCP client asking to log in first asks the server it is connecting to where its authorization server is. A malicious MCP server could answer with its own endpoint, and the affected SDK versions would then send the client secret, the authorization code, and the PKCE proof key straight to it. With those three items, an attacker can redeem the code at the real login service for a valid access token carrying the application's permissions. The client secret is the worst of the three: it is long-lived and stays valid until someone rotates it.
Why machine-to-machine clients were the worst case
The advisory rates the flaw 7.5 out of 10 for the two machine-to-machine OAuth providers and 6.5 for the interactive one. The reasoning follows from the mechanics. Interactive browser flows show the user a genuine login page from the real provider, so a person authenticating sees nothing suspicious. The ClientCredentials and PrivateKeyJWT flows need no user at all, which means an unattended agent could leak a secret to a hostile server with no human ever looking at a screen. Security firm Cycode, which reported the flaw, demonstrated a full account takeover in testing.
The boundary of the bug matters for anyone running models locally. MCP servers built with the SDK are not affected, local stdio connections are not affected, and clients that supply their own tokens are not affected. The risk lives in one specific pattern: an HTTP connection from an SDK-based client to a remote MCP server you do not fully trust, while that client holds credentials for a service you do care about.
What to do if your client touches untrusted servers
Patched versions 1.30.0 and 2.2.0 shipped on 7 September and validate the expected issuer before fetching server metadata, rejecting mismatches. The advisory itself was published on 28 September, alongside Cycode's writeup. No exploitation has been reported.
Upgrading is step one, not the whole job. For the machine-to-machine providers, upgrading alone is not enough: the provider must also be configured with an explicit issuer that pins the real login service, and on version 1.30.0 the warning nudging you to do this is a Python deprecation warning hidden by default. The deprecated RFC7523OAuthClientProvider has no issuer option at all and should be replaced. The advisory also recommends clearing stored OAuth client registrations once after upgrading, and rotating any client secret plus revoking tokens if the client may have connected to an untrusted server.
For teams wiring local agents to remote MCP servers, this is a reminder that the agent's credential store is part of the threat surface. A model running on your own hardware is not safer if its tool layer will hand a long-lived cloud secret to whatever server it connects to. Trust the connection, not just the model.