CyberPeople

Vulnerability in the Official MCP Python SDK Allowed Stealing OAuth Tokens

MCP Python SDK: Vulnerability Allowed Stealing OAuth Tokens

A vulnerability in the official MCP Python SDK allowed a malicious server to steal an app's OAuth credentials and take over the account. Fixed in versions 1.30.0 and 2.2.0.

On September 28, 2026, the maintainers of the official Python SDK for the Model Context Protocol (MCP) published security bulletin GHSA-qx49-fqc8-xw99 about a vulnerability that allowed a malicious MCP server to steal the OAuth credentials of an application connecting to it. This is not about a short-lived session token but about the client secret, the authorization code, and the PKCE key — a set sufficient to obtain a full access token, with all its privileges, on behalf of the application.

The vulnerability was discovered and described by Cycode, a company specializing in software supply-chain security. As of September 29, no CVE identifier had been assigned yet, and fixes were already released in versions 1.30.0 (the 1.x branch) and 2.2.0 (the 2.x branch). No known in-the-wild attacks using this vulnerability were recorded at the time of publication, but the very nature of the problem — theft of long-lived credentials — makes it dangerous for anyone connecting AI applications to external MCP servers.

What happened

Cycode found that an MCP client built on the official SDK, in vulnerable versions, did not always verify which login service (authorization server) the MCP server was pointing it to. A malicious server could point at its own token endpoint and force the application to send sensitive data there: the client secret, a fresh authorization code, and the PKCE key (code_verifier).

With this set, the attacker sends it to the real token endpoint of the actual login service, obtains a valid access token, and completes an account takeover. Cycode demonstrated the full chain against a real authorization server with PKCE enabled. The authorization code is single-use, but the client secret is long-lived: it keeps working until it is changed, so the attacker retains the ability to authorize again and again.

The vulnerability is rated high (CVSS 7.5) for the two machine-to-machine providers and medium (6.5) for the interactive provider, where someone has to start the login. Tellingly, the issuer checks appeared in releases 1.30.0 and 2.2.0 as early as September 7, but were described as a "behavior change" rather than a security fix. The bulletin came out on September 28 — the same day Cycode published its breakdown. This means that for nearly three weeks users could have been updating without even suspecting that the releases closed a security gap.

What MCP is and why it matters

The Model Context Protocol (MCP) is an open standard for connecting AI applications to external tools and data. It was introduced by Anthropic in 2024, and since then the protocol has quickly become the de-facto standard for letting AI agents access databases, repositories, APIs, and enterprise services. The official Python SDK is one of the most popular tools for building MCP servers and clients.

Why exactly are OAuth credentials a critical target? When an MCP client authenticates to a third-party service, it receives a token with the privileges granted to the application. By stealing the client secret and authorization code, an attacker gets the same privileges as the legitimate application — without hacking the service itself. For enterprise scenarios where an agent is delegated access to email, cloud resources, or CI/CD, this means compromising everything the agent could reach. And unlike phishing or social engineering, here the victim may not enter any data at all — it's enough for their application to connect to the "wrong" MCP server.

OAuth token security

Technical breakdown: how the server steals credentials

The attack mechanism is elegant and therefore dangerous. When an MCP client needs to log in, it asks the MCP server where its authorization server — the login service — is located. By specification, the client must verify that this service is the one that owns its credentials (an issuer check). In vulnerable SDK versions, this check was incomplete or entirely absent.

The attacking MCP server could do one of two things: either name its own token endpoint, or return login metadata pointing to the user's real service while routing the credentials themselves elsewhere. The client "trusted" the server's response and sent the client secret, authorization code, and PKCE key wherever the server pointed.

Especially insidious is the PKCE defeat. Proof Key for Code Exchange is a mechanism that exists precisely so an intercepted authorization code cannot be reused. By handing over both the code and the key, the client nullifies that protection. For the interactive provider, a human still has to confirm the login — and the page they see is the real login page, so nothing looks suspicious. The two machine-to-machine providers don't require human involvement at all, which explains their higher CVSS score.

The key detail is the asymmetry between what the user sees and what actually happens. The user sees their service's legitimate login page and confirms the sign-in, while in the background their application handed the secret and code to a third-party server. This "invisibility" is exactly what makes the attack hard to detect with ordinary means.

Who is affected

At risk is an application that simultaneously: uses the SDK as an MCP client over HTTP; uses one of the OAuth providers — OAuthClientProvider, ClientCredentialsOAuthProvider, PrivateKeyJWTOAuthProvider, or the legacy RFC7523OAuthClientProvider (1.x branch); connects to a server it doesn't fully control; and holds credentials for a real login service.

Affected versions: from 1.9.1 to 1.29.1 in the 1.x branch (fixed in 1.30.0) and from 2.0.0 to 2.1.1 in the 2.x branch (fixed in 2.2.0). In other words, almost all recent releases of both branches — the vast majority of real installations — fall under the vulnerability.

At the same time, the vulnerability does not affect MCP servers built on the SDK, local stdio clients, or clients that connect their own tokens without using the OAuth providers. So the threat is concentrated on configurations where a client authorizes via OAuth against a server that can't be fully trusted — typically scenarios of connecting agents to public MCP server directories.

How to protect yourself

The first and main step is to update the SDK to fixed versions 1.30.0 or 2.2.0. In them, the client first determines which login service it expects and rejects any other.

However, updating is not the whole story. For the ClientCredentialsOAuthProvider and PrivateKeyJWTOAuthProvider providers, the fix "changes nothing until you pass the issuer= parameter" — so the bulletin advises. This parameter explicitly names the login service that owns the credentials; without it, the client will still follow whatever server the MCP server points to. In version 1.30.0, the warning about this is a regular deprecation warning that Python hides by default, so it's easy to miss. And the legacy RFC7523OAuthClientProvider has no issuer= parameter at all — you should migrate off it to one of the other two providers.

Additional steps after updating: clear stored OAuth client registrations once, since old entries aren't bound to a login service; if the client could have connected to an untrusted server, change the client secret and revoke tokens on the login service. On old versions, the only way to avoid the problem is to connect only to MCP servers you trust.

Separately, review the list of MCP servers your agents connect to. Every public or third-party server is a potential entry point, and minimizing that list reduces the attack surface. If you already use MCP agents in your projects, it's also worth checking whether your credentials have already "leaked" — you can do this with our breach-check tool.

MCP protocol and AI agents

Timeline of events

A short timeline to understand how "quietly" the fix went through:

  • September 7, 2026 — issuer checks appear in releases 1.30.0 and 2.2.0, described in release notes as a behavior change rather than a security fix.
  • September 28, 2026 — Cycode publishes a detailed breakdown, and the maintainers release security bulletin GHSA-qx49-fqc8-xw99.
  • September 29, 2026 — as of this date no CVE identifier has been assigned, and no known in-the-wild attacks using the vulnerability have been recorded.

So almost three weeks between the "fix" and the "announcement" — time during which some users may have updated accidentally, while others stayed on vulnerable versions, unaware of the risk.

What this means for AI-agent security

This vulnerability is an important wake-up call for the entire young AI-agent ecosystem. MCP is rapidly gaining popularity, and many teams already delegate access to real systems — email, repositories, cloud services, enterprise APIs — to agents. A vulnerability in the official SDK shows that even a "reference" tool can have gaps in the trust between client and server, opening the way to account takeover.

Notably, this is not the first security fix in this SDK recently. Earlier, in version 1.27.2, another issue was closed — CVE-2026-52869, where the SSE and Streamable HTTP transports routed requests into an existing session based only on the session ID, without checking whether it belonged to the same authenticated client. Together, these fixes show that a protocol that quickly became a de-facto standard is now going through an intensive security-hardening period — and that an "official SDK" does not exempt you from vigilance.

Three takeaways for developers and security teams. First, AI agents inherit the same supply-chain and authorization problems as ordinary software — and even more so, because agents are delegated ever-broader privileges. Second, a "security" fix published as a routine behavior change without a clear announcement means some users will update late or not at all — worth watching dependency bulletins more closely than release notes. Third, any external MCP server should be treated as potentially untrusted until you fully control it.

For those just starting with AI agents and wanting to build a sound trust and authorization model, it's useful to start with the basics — our cybersecurity and learning material gathers the fundamentals to start from.

Code security vulnerability

Conclusion

The vulnerability in the official MCP Python SDK is a reminder that even popular and trusted AI-ecosystem tools can contain serious authorization gaps. It allowed a malicious server to steal the client secret, authorization code, and PKCE key, and take over an account on behalf of the application. Fixes are already available in versions 1.30.0 and 2.2.0, but for some providers an explicit issuer= parameter is required.

The main advice is simple: update the SDK, explicitly set issuer for the relevant providers, clear old OAuth registrations, and change secrets if there was a risk of connecting to an untrusted server. And remember the rule this story illustrates better than any other: with AI agents, trust must be explicit and verified, not inherited by default.

Stay ahead of threats

Weekly cybersecurity intelligence in your inbox. No spam.

CyberPeople contributor