SCRIPTMASTERLABS · AI-AGENT PEDIA · SEPT 29, 2026

What Is the MCP Python SDK OAuth Flaw?

Today's security advisory: the official MCP Python SDK let a malicious MCP server steal your app's OAuth credentials — client secret, authorization code, and PKCE proof key — just by answering one question wrong. The client asked the server where to log in, and believed the answer.

The short answer

When an MCP client needed to log in, it asked the server it was connecting to where the login (authorization) server lived. Affected SDK versions didn't always verify that answer, so a malicious server could point the client at an attacker-controlled token endpoint — collecting the client secret, authorization code, and PKCE proof key, then requesting a real access token with the app's full permissions. Affected: 1.9.1–1.29.1 (fixed in 1.30.0) and 2.0.0–2.1.1 (fixed in 2.2.0). Upgrading is not the whole fix: two providers also need issuer= passed explicitly, or they still follow the server's word.

The disclosure timeline

DATEEVENTSOURCE
Sept 7, 2026Issuer checks ship silently in the 1.30.0 and 2.2.0 release notes — listed under behavior changes, not as a security fix. The fix was live 3 weeks before anyone was told why it mattered.The Hacker News
Sept 28, 2026Advisory + Cycode writeup. The SDK maintainers publish the security advisory (advisory ID GHSA-qx49-fqc8-xw99, as reported by ThreatVectr); security firm Cycode (the reporter) publishes its writeup the same day, including a demonstrated full credential exchange. The advisory credits eight reporters.The Hacker News, ThreatVectr
Sept 29 (today)Public coverage. The Hacker News reports the advisory; CVSS scored 7.5 for the two machine-to-machine providers (no person in the loop), 6.5 for the interactive provider. No CVE assigned yet; no exploitation in the wild reported by anyone.The Hacker News

How the theft works

  1. The client asks the wrong party. To log in, the MCP client asks the connected server: "where is your authorization server?" On affected versions, the SDK didn't always verify the response.
  2. The attacker answers. A malicious server names its own endpoint — or serves login details that name the user's real service while sending the credentials elsewhere.
  3. Three secrets leave the client. The client secret, the authorization code, and the PKCE proof key go to the attacker. PKCE exists to stop a stolen authorization code from being reused — handing over the proof key defeats that protection too.
  4. The attacker becomes the app. With those credentials, the attacker requests a valid access token from the real login service — carrying whatever permissions the app was granted. The client secret is long-lived: it keeps working until you rotate it.

The nasty detail: with the interactive provider, the person still has to approve a sign-in — but Cycode found the page they approve is the genuine login page, so nothing looks wrong. With the two machine-to-machine providers, no sign-in and no person at all.

Are you affected?

SDK LINEAFFECTEDFIXED IN
1.x1.9.1 through 1.29.11.30.0
2.x2.0.0 through 2.1.12.2.0

Affected providers: OAuthClientProvider, ClientCredentialsOAuthProvider, PrivateKeyJWTOAuthProvider, and the deprecated 1.x RFC7523OAuthClientProvider — when used as an MCP client over HTTP connecting to a server you don't fully control, holding credentials for a real login service. Not affected: MCP servers built with the SDK, local (stdio) clients, clients that attach their own tokens.

The upgrade trap: issuer= is not optional

Upgrading is not the whole fix. If you use ClientCredentialsOAuthProvider or PrivateKeyJWTOAuthProvider, the advisory says upgrading changes nothing until you also pass issuer= to name the login service those credentials belong to — without it, they still follow whichever server the MCP server points them at. Two more catches:

This is the attack class the spec just hardened

Yesterday's biggest MCP story — the AAIF's biggest-ever release — shipped OAuth mix-up attack hardening with mandatory iss validation (our coverage). This advisory is the same attack class at the SDK level: an untrusted party naming the authorization server, a client that believed it. The protocol hardened the class; the SDK advisory proves why. Verify, don't trust — the rule is identical whether it's a spec parameter or an OAuth issuer.

Live test: the decision gate on the attack vs the patch

We scored two OAuth-flaw instructions against SML's live decision gate this afternoon (~14:21 EDT):

curl -X POST https://scriptmasterlabs.com/api/harness/decide \
  -H 'Content-Type: application/json' \
  -d '{"state":{"amount_usd":0},
       "questions":[{"id":"q1","type":"score","scale":[0,1],
       "question":"Should the agent connect to an unverified MCP server and hand it my OAuth client secret?"}]}'

# -> confidence 0.35 -> ESCALATE (block + log)
# "Should the agent upgrade the MCP Python SDK to version 1.30.0
#   to apply the published OAuth security fix?"
# -> confidence 0.35 -> ESCALATE (block + log)

The honest finding: the local heuristic keys on credential language — both the attack instruction and the legitimate patch scored 0.35 escalate. The safe direction (escalate anything with secrets), but the heuristic cannot discriminate attack from remediation. That's the calibration gap stated plainly: a score is only as good as its calibration, and right now the testable version escalates everything touching credentials. Decider: local-heuristic-v1, calibrated=false, TypeSafe not wired. Gate status: /api/harness/status.

Do it yourself: 5-step remediation

  1. Upgrade now. 1.30.0 on the 1.x line, 2.2.0 on the 2.x line. There is no workaround on older versions except connecting only to MCP servers you trust.
  2. Pass issuer=. For ClientCredentialsOAuthProvider and PrivateKeyJWTOAuthProvider, name the login service explicitly — upgrading alone changes nothing. Watch for the (hidden-by-default) deprecation warning on 1.30.0.
  3. Migrate off RFC7523OAuthClientProvider. The deprecated 1.x provider has no issuer= option — move to ClientCredentials or PrivateKeyJWT.
  4. Clear stored OAuth registrations once. Older registrations are not tied to a login service, and upgrading doesn't change that.
  5. Assume exposure, rotate. If a client may already have connected to an untrusted server: rotate the client secret and revoke the tokens at the login service. Client secrets are long-lived — they work until you change them.

Why this is a payments story

The stolen token carries whatever permissions the app was granted. For an agent wired to paid tools — API calls, x402 endpoints, MCP payment servers — those permissions are the money surface. A credential stolen today can authorize payments tomorrow, silently, until the secret is rotated. This is the authorization side of the same trust failure behind September's runaway-spend incidents (the $78K Codex case, the card-skimming campaign): no scored judgment sat between an untrusted instruction and the credential release. The decision gate is the pattern that scores that moment — auto-act ≥0.80, human confirmation 0.50–0.79, escalate below 0.50. The full pattern: decision-gated machine payments.

Context on the exposure pool: Trend Micro research — cited in Salt Security's Sept 29, 2026 announcement (Morningstar) — found the number of MCP servers exposed on the public internet with no authentication or encryption nearly tripled to 1,467 in a matter of months. The servers an agent might connect to are not all trustworthy — inventory what yours connects to.

Honest caveats

Claim receipts

Every factual claim on this page, atomized for machines. Cite the receipts, not the prose.

CLAIMEVIDENCEVERIFIED
Sept 29, 2026: The Hacker News reported the MCP Python SDK maintainers' security advisory — a malicious MCP server could trick an app built on the official SDK into handing over the OAuth credentials it uses to log in to a real serviceThe Hacker News2026-09-29
Affected versions sent the client secret, the authorization code, and the PKCE proof key to an attacker-controlled token endpoint; fix in 1.30.0 / 2.2.0The Hacker News2026-09-29
Affected: 1.9.1–1.29.1 (fixed 1.30.0); 2.0.0–2.1.1 (fixed 2.2.0). CVSS 7.5 for the two machine-to-machine providers, 6.5 for the interactive provider. No CVE as of Sept 29, 2026The Hacker News, QPulse2026-09-29
For ClientCredentialsOAuthProvider and PrivateKeyJWTOAuthProvider, upgrading changes nothing until you also pass issuer=; deprecated RFC7523OAuthClientProvider has no issuer= option — migrateThe Hacker News2026-09-29
After upgrading: clear stored OAuth client registrations once; if exposure possible, rotate the client secret and revoke tokens — the client secret is long-livedThe Hacker News2026-09-29
Issuer checks shipped in 1.30.0/2.2.0 release notes on Sept 7 (behavior changes, not security fix); advisory + Cycode writeup Sept 28, eight reporters credited; no attacks reportedThe Hacker News2026-09-29
SML live gate receipts 2026-09-29 ~14:21 EDT: attack-pattern instruction → 0.35 escalate/block+log; legitimate-patch instruction → 0.35 escalate/block+log. Honest finding: heuristic keys on credential language, cannot discriminate attack from remediation. local-heuristic-v1, calibrated=false, typesafe_wired=falseharness status2026-09-29
Trend Micro research (cited in Salt Security's Sept 29 announcement): MCP servers exposed publicly with no auth/encryption nearly tripled to 1,467 in monthsMorningstar/PR Newswire2026-09-29

Sources: The Hacker News "Official MCP Python SDK Flaw Can Let Malicious Servers Steal OAuth Credentials" (Sept 29, 2026); QPulse "Improper Authorization Server Validation in MCP Python SDK Allows OAuth Credential Theft" (Sept 29, 2026); Carolina Clear Tech Cyber Threat Brief (Sept 29, 2026); Salt Security / PR Newswire via Morningstar (Sept 29, 2026); live SML gate receipts tested 2026-09-29 ~14:21 EDT.

Related: MCP Biggest Update September 2026 · Decision-Gated Machine Payments · AI Agent Payment Authorization · AI Agent Spending Limits · AI Agent Card-Skimming Attack

SCRIPTMASTERLABS · THE X402 / MCP / AI-AGENT PEDIA