Back to blog
MCPOAuthidentitySDKtool use

MCP Python SDK: one malicious server was enough to collect your client secret

Published on 2026-09-296 min readActionShield

> TL;DR: A malicious MCP server could trick the official MCP Python SDK client into sending its client secret, authorization code and PKCE proof key to an attacker-controlled token endpoint. The flaw was fixed on September 7 in versions 1.30.0 and 2.2.0 — but the advisory is dated September 28: many deployments are still running affected versions.

The mechanism: the server answers the client's question

The SDK's OAuth flow works like this: the client asks the MCP server where the authorization server is. The server answers. That is where everything hinges.

In the affected versions, the SDK validated that answer insufficiently. A malicious server could return an attacker-controlled token endpoint — and the client would send the client secret, authorization code and PKCE proof key to it.

Cycode reported the flaw and demonstrated a full credential exchange: the stolen credentials are redeemed for a valid access token carrying the application's permissions. And the client secret is long-lived: exchange it once, and you have it for a long time.

Who is affected

  • 1.x: 1.9.1 through 1.29.1 — fixed in 1.30.0
  • 2.x: 2.0.0 through 2.1.1 — fixed in 2.2.0
  • Affected providers: OAuthClientProvider, ClientCredentialsOAuthProvider, PrivateKeyJWTOAuthProvider, and the deprecated RFC7523OAuthClientProvider on 1.x. CVSS 7.5 for the two non-interactive providers, 6.5 for the interactive provider. No CVE assigned to date, no known active attacks.

    What the upgrade does not do

    This is the part most teams will miss:

  • `ClientCredentialsOAuthProvider` and `PrivateKeyJWTOAuthProvider` now require an `issuer=` parameter after the upgrade. Without it, the fix does not apply.
  • `RFC7523OAuthClientProvider` has no `issuer=`: it is deprecated, you must migrate.
  • Clear the saved OAuth client registration once after upgrading — otherwise the client will reload the old discovery answer.
  • If your client connected to an untrusted server: rotate the client secret and revoke tokens. The upgrade does not recover what was already sent.
  • In 1.30.0, the warning is a standard Python deprecation warning, hidden by default. It does not blink anywhere.

    What to check right now

  • List your MCP Python SDK versions in every client authenticating via OAuth. 1.9.1 and later, 2.0.0 and later: affected.
  • Verify `issuer=` is passed for the non-interactive providers, after upgrading.
  • Identify the MCP servers your clients connected to — "untrusted" includes every server you did not deploy yourself.
  • What is not affected: MCP servers built with the SDK, local stdio clients, and clients that attach their own tokens.
  • The takeaway

    In the OAuth flow, the MCP server is the least trustworthy part of the chain — and yet it decides where the client sends its secrets. A client that trusts the discovery answer of any server makes the same mistake as a browser that follows a redirect without checking. The simple rule: an identity must never depend on the answer of an uncontrolled third party.

    Building software? CleanIssue performs security audits for your product in real-world conditions, no source code access needed. For a first read of your exposure, start with an external review of your application.

    Want to know what your AI agent can do?

    Tell us about your agent, its tools, and client context. We will come back with the right review scope.

    Discuss your audit