Three security advisories for the official MCP SDKs contain the same sentence, in bold: "Upgrading alone changes nothing." [1] [2] [3]
That sentence matters because of how most teams find out about a vulnerability. A scanner compares the version in your lockfile with the affected range in the advisory. Once you move past the patched version, the alert closes and the dashboard turns green. For these three advisories, the green dashboard describes a server that is exactly as exposed as it was the day before, because the fix ships switched off.
They arrived in a batch of nine advisories for the TypeScript and Python SDKs, added to the GitHub Advisory Database on October 20 and October 27. Read together, the nine fall into four kinds of fix, and only one kind does all its work when you change a version number.
Nine advisories, four kinds of fix
The SDK repositories published these between September 28 and October 15. The GitHub Advisory Database, which feeds most dependency scanners, listed them five to twenty-nine days later. None of the nine reports any exploitation.
| Advisory | SDK | CVSS | The problem | What upgrading does |
|---|---|---|---|---|
| GHSA-22jm-h49p-29qw | TypeScript | 8.6 | Experimental tasks not tied to the session that created them [7] | Fixes it. The feature is deprecated; stop using it |
| GHSA-jm63-cq47-j5jp | TypeScript | 7.7 | Shared server instances delivered one client's messages to another [4] | Fixes it by refusing to run the shared pattern |
| GHSA-46jr-4wx8-v453 | TypeScript | 7.5 | One request under the size limit could exhaust server memory [1] | Nothing, until you set an option |
| GHSA-f897-62hf-6gxq | TypeScript | 7.5 | No limit on request body size or batch length [6] | Fixes it with new defaults |
| GHSA-rvq5-wwqv-78pq | TypeScript | 6.8 | Bearer auth accepted tokens issued for another service [2] | Nothing, until you set an option |
| GHSA-w4fh-qvv9-3v23 | Python | 6.8 | The same token audience gap [3] | Nothing, until you set an option |
| GHSA-rwrf-2pqf-9j8j | Python | 6.5 | Client fetched URLs that a server chose in a tool's output schema [8] | Fixes it |
| GHSA-6prh-2h8m-c8cw | TypeScript | 6.5 | Client followed cross-origin redirects with headers and bodies [5] | Fixes it, but cannot recall what already leaked |
| GHSA-5h93-6whr-6q8j | Python | 5.9 | The same redirect problem [9] | Fixes it, no code changes needed |
The four kinds are: fixes that work on upgrade, a fix that breaks your app until you change code, fixes that cannot undo past exposure, and fixes that do nothing until you turn them on. The last kind is where a green scan misleads you.
The three fixes that ship off
Tokens meant for someone else
The most consequential pair concerns authentication. Where one authorization server issues tokens for several services, the SDKs' bearer authentication had no way to check that a token was issued for your server. A valid token for a different service was accepted by your MCP server too [2] [3].
The protocol has never allowed this. The 2026-07-28 specification's security guidance states it in one line: "MCP servers MUST NOT accept any tokens that were not explicitly issued for the MCP server." [10] The SDKs simply gave you no built-in way to comply.
The patched versions add that way, and leave it off. In TypeScript you need two changes together [2]:
// 1. Tell the middleware which audience your tokens must carry
app.use(requireBearerAuth({
verifier,
expectedResource: new URL('https://mcp.example.com/mcp'),
}));
// 2. In verifyAccessToken(), return the token's audience as a URL
return { ...authInfo, resource: new URL(claims.aud) };
Python works the same way: set validate_token_resource=True and resource_server_url in AuthSettings, then return the token's audience from verify_token() as AccessToken.resource [3].
The advisories add a detail worth reading twice. With only the first change, every request gets 401 [2] [3]. A team that does half the work finds out in minutes, because nothing works. A team that does none of the work finds out never, because everything works, including tokens minted for the billing service.
Python has announced an end date: the setting will default to True in 3.0, and until then there is a deprecation warning, which the advisory tells teams whose verifier already checks the audience to silence with validate_token_resource=False [3]. The TypeScript advisory names no such date.
You are only exposed if your authorization server also issues tokens for other services and your verifier does not already check aud itself. Small single-purpose deployments often fall outside that. Shared corporate identity providers often fall inside it.
One small request, all the memory
The third off-by-default fix is a denial of service. Servers put no limit on how many array elements and object keys they validated in one request. A single HTTP request inside the default 4 MiB body limit could exhaust memory until the process died with JavaScript heap out of memory. No credentials are needed unless you authenticate before the SDK sees the request [1].
The patch adds maxToolInputElements to McpServer, off by default [1]:
const server = new McpServer(info, { maxToolInputElements: 10_000 });
The advisory asks for a second change too: lower the request size limit to what your tools need, through maxRequestBodySize on the transport or createMcpHandler(), or through your own parser if you use express.json() or Fastify [1]. That limit itself came from a separate advisory, which gave the SDK its 4 MiB default, a 413 above it, and a 400 for batches of more than 100 messages [6]. That one does fix itself on upgrade. Together they show the pattern: the SDK now has a ceiling, and the ceiling is generous.
Why ship a fix switched off
It is tempting to call this negligence. It is closer to the opposite.
An audience check that is on by default would reject every token on every server whose verifier does not yet report an audience. The advisories prove it with their own warning about half-done changes. Turning that on in a minor release would take down working deployments that were never exposed, to protect the subset that is. An element limit on by default needs a number, and the right number depends on your largest legitimate tool input, which the SDK cannot know.
So the maintainers made a defensible trade: nothing breaks on upgrade, and the advisory text carries the rest of the fix. The cost of that trade lands on whoever reads the advisory, and on nobody who only reads the scanner.
The fix that breaks your app on purpose
One advisory went the other way. In the 2.x server package, clients that shared one stateless transport, or one McpServer instance, could receive each other's responses and notifications. Messages were matched to a connection by JSON-RPC id alone, and SDK clients number their requests from 0, so ids collide in normal use [4].
The advisory admits where the pattern came from: until this release, the README examples for the Hono, Express, Fastify and Node adapters created the server once at startup [4]. Teams that copied the docs copied the bug.
The patched version refuses to be shared. A second connect() rejects with ALREADY_CONNECTED, and a stateless transport rejects its second request [4]. Upgrading breaks an affected app, loudly, until you build a new server per request, per session, or through a createMcpHandler() factory. This is the same per-request design that the stateless 2026-07-28 specification pushes toward.
Compare the two approaches. The loud fix will get applied, because a broken app gets attention within the hour. The quiet fixes depend on someone reading to the bottom of an advisory.
The fix that cannot reach backwards
The TypeScript redirect advisory is a reminder that patching stops future damage and does nothing about past damage. The client transports and OAuth requests followed redirects to any origin, so a cross-origin redirect could carry custom headers such as an X-API-Key, and on a 307 or 308 the request body too, including OAuth token requests with their refresh_token and client_secret [5].
Version 1.32.0 limits redirects to the same origin. The advisory then adds the step a version bump cannot do: if a redirect may have reached a host you do not control, rotate the API keys and client_secret your application held and revoke its tokens [5]. It also names the way back into the hole: redirectPolicy: 'follow' restores the old behavior and the exposure. The Python equivalent needs no code changes on upgrade [9].
What we checked on our own server
This site runs a public MCP server at /api/mcp. It is hand-written, not built on either SDK, so none of the nine advisories applies to it directly. The questions they raise still apply to any MCP server, so on November 4 we sent it three requests to see how it handles them.
| Request | Result |
|---|---|
| A 100 KB body | 413, "Request body too large", in 546 ms |
| A batch of two JSON-RPC messages | 400, "Batches are not supported", in 66 ms |
A 61 KB search_articles call with an unused 12,000-element array argument |
Normal search results in 400 ms |
The body limit is 64 KB. The large array was harmless because the server reads only the arguments it knows by name, caps text arguments at 200 characters, and never walks the rest. The audience question does not arise, because the server is read-only, public and accepts no tokens at all.
That is three requests from one machine, not a load test, and a hand-written server has its own risks that no SDK advisory will ever cover. The useful part is the method: each advisory's "Am I affected?" section translates into a request you can send to your own endpoint in a minute.
A checklist that a scanner cannot run
If you run an MCP server or client on either official SDK, these are the checks that a version number will not answer:
- Bearer auth over HTTP? Confirm that
expectedResource(TypeScript) orvalidate_token_resource=True(Python) is set and that your verifier returns the token's audience. Test with a token issued for a different service and expect401[2] [3]. - Tool inputs with arrays or records? Set
maxToolInputElementsjust above your largest real input, and lowermaxRequestBodySizefrom 4 MiB to what your tools need [1]. - Server created once at startup? Search your code for a module-level
new McpServeror a shared transport. Upgrading to@modelcontextprotocol/server2.3.0 will break it, which beats the alternative [4]. - Custom headers or OAuth secrets on a client? Upgrade, make sure no transport sets
redirectPolicy: 'follow', and rotate the secrets if you cannot rule out a cross-origin redirect in the past [5]. - Experimental tasks? Remove
taskStore. The feature is deprecated [7].
The current releases at the time of writing are @modelcontextprotocol/sdk 1.32.2, @modelcontextprotocol/server 2.4.0 and mcp 2.3.0 for Python, all past every patched version in the table.
For more on how MCP authorization got here, see MCP Shipped Identity for Humans. Agents Are Still a PR.
A version number tells you which code you are running. It has never told you which of its protections you turned on.
References
[1] MCP TypeScript SDK maintainers (GitHub Security Advisory): One HTTP request within the default size limit could exhaust server memory during validation (CVE-2026-111768) (2026-10-20). Documentation
[2] MCP TypeScript SDK maintainers (GitHub Security Advisory): Server bearer authentication accepted tokens issued for another service (CVE-2026-111771) (2026-10-20). Documentation
[3] MCP Python SDK maintainers (GitHub Security Advisory): Server bearer-token authentication accepts tokens issued for a different resource server (CVE-2026-116684) (2026-10-27). Documentation
[4] MCP TypeScript SDK maintainers (GitHub Security Advisory): Shared transport or server instances delivered one HTTP client's messages to another (CVE-2026-111770) (2026-10-20). Documentation
[5] MCP TypeScript SDK maintainers (GitHub Security Advisory): HTTP client transports and OAuth requests followed cross-origin redirects (CVE-2026-111769) (2026-10-20). Documentation
[6] MCP TypeScript SDK maintainers (GitHub Security Advisory): HTTP server transports and handlers did not limit request body size or JSON-RPC batch length (2026-10-27). Documentation
[7] MCP TypeScript SDK maintainers (GitHub Security Advisory): Experimental tasks were not tied to the session that created them (CVE-2026-111767) (2026-10-20). Documentation
[8] MCP Python SDK maintainers (GitHub Security Advisory): Client fetched server-chosen $ref URLs while validating tool results (CVE-2026-116686) (2026-10-27). Documentation
[9] MCP Python SDK maintainers (GitHub Security Advisory): HTTP client transports followed cross-origin redirects carrying custom headers and bodies (CVE-2026-116685) (2026-10-27). Documentation
[10] Model Context Protocol: Security Best Practices (specification 2026-07-28). Documentation