跳到正文
DEV Community· Actionable Vectors·· 4 小時前AI 評分72

MCP TypeScript SDK 的 @modelcontextprotocol/server 2.0.0–2.2.0 存在 HTTP 回應串線漏洞,2.3.0 修復

Whose response is this? The MCP server SDK that matched replies by id alone

AI 導讀

MCP TypeScript SDK 維護者在 @modelcontextprotocol/server 2.3.0 修復 CVE-2026-111770,該漏洞會令共用 HTTP transport 或 server instance 的不同用戶收到彼此的回應及通知。

正文

Whose response is this? The MCP server SDK that matched replies by id alone

A vector breakdown of CVE-2026-111770 / GHSA-jm63-cq47-j5jp (@modelcontextprotocol/server 2.0.0 through 2.2.0, fixed in 2.3.0)

No injection, no stolen token. Two people use the same MCP server over HTTP at the same time, and one of them gets the other's answer. That's the whole bug, and it came straight from the pattern the official framework examples showed.

What the advisory actually says

From GHSA-jm63-cq47-j5jp, published by the MCP TypeScript SDK maintainers and added to the GitHub Advisory Database on October 20, 2026:

  • Package: @modelcontextprotocol/server (npm). Affected: 2.0.0 through 2.2.0. Fixed: 2.3.0.
  • Not affected: stdio servers, createMcpHandler() with a factory that builds a new server on every call, and @modelcontextprotocol/sdk 1.26.0 and later.
  • Weakness: CWE-362, a race on a shared resource. Severity: High, CVSS 3.1 7.7 (AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:H).
  • The bug: "an MCP server reached over HTTP could deliver one client's responses and notifications to another client. This happened when clients shared one stateless transport, or one McpServer or Server instance."
  • Why ids collide: "Messages were matched to a connection by JSON-RPC id alone. SDK clients number requests from 0, so ids collide in normal use."
  • Credit: DavidCarliez and legitu1337.

It's one of five MCP TypeScript SDK advisories published the same afternoon. The others cover session-unbound tasks, a validation memory blowup, a missing token audience check, and headers resent across redirects.

The vector: two clients, one connection table

  1. A developer builds an HTTP MCP server the way the README examples for the hono, express, fastify and node adapters showed: create the server and transport once at startup, then reuse them for every request.
  2. Client A sends a request with JSON-RPC id 0. Client B, an unrelated user, also sends id 0, because every SDK client starts counting at 0.
  3. The shared instance has one slot for "the response to id 0." Whichever response is ready gets routed to whichever connection currently holds that id.
  4. Client B receives client A's tool result, or A's notifications, which may hold whatever data A's tool returned.

The attack complexity is rated high because it depends on timing and overlap. But this isn't something an attacker has to engineer. It happens on its own whenever traffic overlaps, so ordinary users can see each other's data without anyone trying.

Why this class of bug exists: three root causes

1. A protocol-level id used as a security identity

Mechanism. JSON-RPC ids exist so one client can match its own replies. They're only unique within one connection. A server that uses them across connections is using a counter as if it were an identity.

Evidence. The advisory: messages were "matched to a connection by JSON-RPC id alone," and because clients "number requests from 0, … ids collide in normal use."

What fixes it. Route by connection or session first, then by id. Any lookup keyed on something the client chooses needs a server-assigned scope around it.

2. "Stateless" read as "safe to share"

Mechanism. A stateless HTTP transport sounds like it holds nothing, so creating one at startup and sharing it looks like a harmless optimization. But it still tracks in-flight requests, and that tracking is state.

Evidence. Affected setups are ones where "your code creates the transport or the server once at startup, instead of once per request or per session." The fix makes the SDK refuse sharing outright: "a second connect() rejects with ALREADY_CONNECTED, and a stateless transport rejects its second request."

What fixes it. Treat per-request objects as per-request. If an object tracks anything in flight, it belongs to one request or one session. Making misuse fail loudly, as 2.3.0 does, is the right default.

3. The insecure pattern was the documented one

Mechanism. Most people build servers by copying the quickstart. If the quickstart shares one instance, most servers will too, and the bug spreads by copy-paste.

Evidence. The advisory: "Until this release, the README examples of @modelcontextprotocol/hono, express, fastify and node showed that pattern."

What fixes it. Example code is security-relevant code. Review quickstarts with the same care as the library, and design APIs so the copy-pasted shape is the safe one, for example a factory that builds a fresh server per call.

How this connects to the rest of the batch

Several of this week's MCP SDK advisories share a theme: something that should have been scoped to one client wasn't. Tasks weren't bound to sessions, tokens weren't bound to an audience, and here responses weren't bound to a connection. In a multi-user agent server, everything keyed by a client-chosen value needs a server-owned scope around it.

Defensive takeaways you can check this week

  • Check your version and your wiring. If you use @modelcontextprotocol/server 2.0.0 through 2.2.0 over HTTP, look for a server or transport created once at startup and reused across requests.
  • Upgrade and change the code. Move to 2.3.0 or later, then switch to one of the patterns the advisory lists: createMcpHandler() with a factory, a new server and transport per request, or one of each per session with sessionIdGenerator set. Upgrading alone will break a shared setup, on purpose.
  • Can't upgrade yet? The advisory says the same code change fixes affected versions.
  • Pick up the rest of the batch. Moving to @modelcontextprotocol/server / client 2.3.0 or @modelcontextprotocol/sdk 1.32.0 also covers the sibling advisories. Note that the validation-memory fix needs its new limit option configured; upgrading alone doesn't enable it.
  • Assess exposure. If several users shared an affected HTTP server, consider whether tool results could have held sensitive data, and handle it the way you'd handle any cross-tenant leak.
  • Test it. Run two clients concurrently against your server with overlapping request ids and assert each receives only its own responses.

Sources


If you're building agent backends and want a checklist for this kind of trust boundary, the Trust Boundary pack covers it.

This article was drafted with AI assistance and edited by a human. All facts come from the advisories linked above.

來源:DEV Community · dev.to