Yaamlabs
AI security

MCP SDK fixes: the token audience check ships switched off

Official MCP SDKs accepted tokens issued for other services and leaked API keys on redirects. Fixed versions, the opt-in setting and how to check.

By Yaali. October 28, 2026, 6 min read, AI security, Vulnerabilities, Identity.

Cover illustration of access key cards passing between server towers through a gate, with the Yaamlabs logo and the text: MCP SDK fix leaves the audience check off, 1.30.0, upgrade plus one setting

On October 27 the GitHub Advisory Database published three CVEs in the official Python SDK for the Model Context Protocol (MCP), the protocol AI agents use to call outside tools, plus a high-severity advisory in the TypeScript SDK. The most important one, CVE-2026-116684 (CVSS 6.8), means an MCP server built on the SDK's bearer authentication would accept a valid access token that was issued for a different service. The TypeScript SDK had the same flaw, published a week earlier as CVE-2026-111771.

You are affected if you build MCP servers or clients with the mcp package on PyPI (1.8.0 to 1.29.1, or 2.0.0 to 2.1.1) or @modelcontextprotocol/sdk on npm before 1.32.0. Dependabot and other scanners that read the advisory database can now flag these versions. The catch is that upgrading alone does not fix the audience flaw: the new check is off by default and needs a setting plus a small code change.

How the token audience flaw works: one authorization server issues tokens for several services, a user or service holding a token for the CRM sends it to the MCP server, the SDK checks only that the signature is valid, and the MCP server accepts it. After the fix with validate_token_resource on, the aud claim is compared with the server's resource URL and a token for another service gets 401

How it works

Tokens for another service

Many companies run one authorization server, such as Entra ID, Okta or Keycloak, that issues OAuth access tokens for several internal services. Each token carries an audience claim (aud) that names the service it was issued for. A resource server is supposed to reject any token whose audience is not itself, even if the signature is valid.

The Python SDK's server-side bearer authentication (AuthSettings with a token_verifier) had no built-in audience check, and neither did requireBearerAuth() or verifyBearerToken() in the TypeScript SDK. If your own verify_token() or verifyAccessToken() only checked the signature and expiry, a token that a user or service legitimately held for, say, a CRM API also opened your MCP server. Any service that receives tokens could then replay them against your MCP tools, and a user scoped to one app reaches another. The CVSS vector reflects that: high confidentiality and integrity impact, but an attacker needs a valid token from the same authorization server first.

Credentials forwarded on redirects

CVE-2026-116685 (CVSS 5.9) is on the client side. The Python SDK's Streamable HTTP and SSE (Server-Sent Events) transports followed HTTP redirects to any host. When a configured MCP endpoint redirected to another origin, custom headers such as an X-API-Key went with the request, and on 307 and 308 redirects so did the request body. The SDK's OAuth client had the same behaviour for discovery, client registration and token requests. A plain Authorization header was safe, because httpx already drops it across origins.

The attacker needs a way to make a trusted endpoint redirect elsewhere: a stale redirect to a domain that has lapsed, a misrouted proxy rule, or redirect logic they can influence. The TypeScript client had the matching flaw (CVE-2026-111769), where an OAuth token request carrying the refresh_token and client_secret could be re-sent to the new origin.

Schema references fetched by the client

CVE-2026-116686 (CVSS 6.5) affects Python clients that call tools on servers they do not control. When a server declared an outputSchema for a tool, the client validated each result with the jsonschema library's default resolver, which opens any $ref URL it cannot resolve locally. A malicious server could point that reference at an http://, https:// or file:// location, and the client would request it from its own network position on every call. The fetched content was not sent back, so the impact is server-side request forgery (SSRF) and denial of service: the fetch ran on the event loop with no timeout, so one slow target could freeze every session in the process.

No request limits in the TypeScript server

GHSA-f897-62hf-6gxq (CVSS 7.5, no CVE assigned) covers TypeScript MCP servers on Streamable HTTP. They had no cap on POST body size or on the number of messages in a JSON-RPC batch, so an unauthenticated client could exhaust memory or tie the server up. The advisory notes that express.json() does not help, because it does not limit batch length.

What attackers are doing

None of the advisories reports exploitation in the wild, and no public exploit is listed. The fixes shipped weeks before the CVEs went public: Python mcp 1.30.0 and 2.2.0 on September 7, and @modelcontextprotocol/sdk 1.32.0 on October 2. The advisories went into the public database on October 27. Anyone with a pinned older SDK in a container image or lockfile is the exposed group, and the redirect flaw only pays off for an attacker who can first control a redirect.

What to do

Table of five advisories in the Python and TypeScript MCP SDKs with CVSS scores and fixed versions, and four steps: upgrade every copy, turn on the audience check, check aud yourself if you cannot patch, and rotate keys that may have leaked

  1. Find every copy. Run pip show mcp or uv pip list | grep mcp in each Python environment, and npm ls @modelcontextprotocol/sdk @modelcontextprotocol/server @modelcontextprotocol/client in Node projects. Check container images and vendored agent tools, not only the main repo.
  2. Upgrade. Python: mcp 1.30.0 or 2.2.0 or later. TypeScript 1.x: @modelcontextprotocol/sdk 1.32.0 or later, which also covers the 1.30.1 request-limit fix. TypeScript 2.x: @modelcontextprotocol/server 2.3.0, @modelcontextprotocol/client 2.3.0, @modelcontextprotocol/node 2.1.0, @modelcontextprotocol/hono 2.0.1 and @modelcontextprotocol/express 2.0.2, for whichever you use.
  3. Turn the audience check on. In Python, set validate_token_resource=True in AuthSettings, set resource_server_url to the audience your authorization server puts in tokens for this server, and return the token's audience from verify_token() as AccessToken.resource. In TypeScript, pass expectedResource: new URL('https://your-server/mcp') to requireBearerAuth() and return AuthInfo.resource from verifyAccessToken(). Make both changes together: with only the first, every request gets a 401. The Python setting becomes the default in 3.0.
  4. If you cannot upgrade today, reject any token whose aud does not include your server inside your own verifier. The advisories say that closes the audience flaw on every affected version. For redirects, pass your own httpx client with follow_redirects left at False (http_client= or httpx_client_factory=) in Python, or a fetch with redirect: 'error' in TypeScript. Cap request bodies at your reverse proxy for the TypeScript server.
  5. Expect one breaking change. Patched clients refuse cross-origin redirects. If your MCP server sits behind a redirect to another host, set the endpoint URL to the final address.

To check whether the audience flaw was used, compare the aud claim of tokens your MCP server accepted with its own resource URL. If you log decoded token claims or authorization server sign-in events, look for tokens issued to other client applications or audiences that reached the MCP endpoint. For the redirect flaw, check client and proxy logs for 3xx responses from your MCP endpoints that point to another host. If you find any, rotate the API keys and OAuth client_secret those clients held and revoke their refresh tokens.

The wider lesson

A dependency scanner marks an advisory as resolved once the version in the lockfile is past the fixed release. For the two audience CVEs that is wrong: the patched SDK still accepts foreign tokens until someone sets the option and changes the verifier. When an advisory says a fix is opt-in, track the configuration change as its own ticket, and add a test that sends a token with the wrong audience and expects a 401, so a later refactor cannot quietly undo it.

We test MCP servers and the agents that call them as part of web application penetration testing, and review agent integrations in AI-native systems work. If you want to know whether your MCP server would accept a token meant for something else, open the chat and Yaali, our AI agent, will pass your question to an engineer.


Sources: GitHub Advisory GHSA-w4fh-qvv9-3v23, GitHub Advisory GHSA-5h93-6whr-6q8j, GitHub Advisory GHSA-rwrf-2pqf-9j8j, GitHub Advisory GHSA-f897-62hf-6gxq, OSV GHSA-rvq5-wwqv-78pq, OSV GHSA-6prh-2h8m-c8cw, NVD CVE-2026-116684, MCP Python SDK security advisories, PyPI mcp release history.

Read next

Back to the blog, or tell us about your system in the chat. Yaali, our AI agent, answers first and brings in an engineer.