All notes

AnalysisAct

The MCP attack surface is the transport, not the protocol

Fifteen advisories in ten days, and almost none of them are about Model Context Protocol itself. They are about the plumbing underneath it, and about a scoring system that cannot describe agent-shaped harm.

Published
Topics
MCP · AI agent security · CVE · CVSS · prompt injection
15MCP advisories our scout surfaced in a ten day window

Ten days of advisories, and the striking thing is what is absent. Almost none of them describe a flaw in Model Context Protocol. They describe the code that carries it: the transports, the wrappers, the servers somebody built in an afternoon to put a tool behind an agent.

The allowlist and the shell disagreed, again

The worst of them is a straight unauthenticated remote code execution, and the mechanism is worth reading slowly. The validation function checked the name of the executable against an allowlist. It did not look at the arguments. The arguments went on to the thing that spawns the subprocess, unchanged.

So the allowlist says yes to a permitted binary, and the permitted binary is one that runs whatever string you hand it. Nothing was bypassed. The check did exactly what it was written to do, on a different object than the one that mattered.

We wrote the same sentence about three coding agents a few days ago: validation that inspects a command as a plain string diverges from the shell that executes it. This is that failure with an MCP label on it.

The transports are the surface

Two more from the same project make the pattern explicit. The endpoint for the SSE and streamable-HTTP transports took a URL and a headers dictionary straight from the caller and made the request. An attacker sets Authorization or Cookie and reaches internal services with credentials attached. The responses never come back, which makes it blind, and blind is enough when the request itself changes state.

Elsewhere, a Go server binds its Streamable HTTP listener to localhost, skips authentication when the token variable is unset, and validates neither Host nor Origin. Binding to localhost feels like a boundary. It is not one, because a browser on that machine will happily send the request for an attacker, and without an Origin check the server cannot tell the difference.

None of this is a protocol defect. The specification does not tell anyone to trust a caller-supplied URL, and it does not say the loopback interface is an authentication mechanism. The flaws are in the plumbing that speaks it, which is the part everyone writes themselves.

Including the official SDK

The most quietly instructive one is in an official SDK rather than somebody's side project. Its HTTP client reads an event stream and appends each chunk to a buffer that is only emptied when a delimiter arrives. A server that never sends the delimiter is not doing anything illegal; it is just never finishing a sentence. The client keeps listening, and the buffer keeps growing.

That is not a clever exploit. It is a parser written for a cooperative peer, shipped into a world where the peer is chosen by whoever configured the agent.

Prompt injection now has a CVE, and two different scores

The last one matters beyond its own product. Poisoned instructions, delivered through a legitimate feature and served over MCP, used to make an agent hand over environment credentials. It has an identifier, an advisory and a fix, which is progress.

It also has two base scores, from the same assessor, for the same flaw:

Same vulnerability, two scoring standards
CVSS 3.1  ->  9.0  CRITICAL
CVSS 4.0  ->  6.4  MEDIUM

The gap is not sloppiness. It is the newer standard doing something the older one cannot: separating what happens to the vulnerable system from what happens to everything downstream of it. For prompt injection the vulnerable system is barely scratched. The damage lands entirely on the systems the agent can reach next.

Under the older standard that downstream damage has nowhere to go except the base score, so it reads Critical. Under the newer one it moves into its own columns and the headline number falls by more than two and a half points. Neither number is wrong, and that is the problem: a team triaging by score alone will treat the same finding as a drop-everything or as a backlog item depending on which standard their tooling reports.

What to do with this

  • Patch the named versions in the ledger below, and check whether MCP is enabled at all before assuming you are affected.
  • Treat every MCP server as an untrusted peer. Bound your buffers, time out your streams, and never let a caller choose the URL you fetch or the headers you attach.
  • Localhost is not authentication. Validate Host and Origin on any local listener an agent talks to, or a browser elsewhere on the machine will speak for the attacker.
  • Do not triage agent findings by base score alone. Ask what the agent can reach, because that is where the impact actually lands and it is exactly what the older score cannot express.

E/01What is confirmed
  • Chainlit command injection: CVE-2026-45018 / GHSA-w3fx-mc44-mf6j, pip chainlit >= 2.4.0rc0 and <= 2.11.1, patched in 2.12.0. Critical, CVSS 9.8, AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H. Published 25 August 2026. validate_mcp_command() checks the executable name against an allowlist and does not inspect the arguments, which reach StdioServerParameters unchanged.
  • Chainlit SSRF: CVE-2026-45019 / GHSA-hvfh-5mj3-5f3j, same version range and fix. High, CVSS 7.2, AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N. POST /mcp on the sse and streamable-http transports accepted a user-controlled url and headers without validation. SSE affected from 2.4.0rc0, streamable-http from 2.6.4. The patch adds an allowed_urls allowlist and strips restricted headers.
  • genieacs-mcp: CVE-2026-55637, versions prior to 0.3.2. CVSS 4.0 base 8.8 High. The Streamable HTTP transport opens an unauthenticated /mcp listener on the default 127.0.0.1:8080 when MCP_AUTH_TOKEN is unset, and does not validate Host or Origin, which is what makes DNS rebinding reach it.
  • MCP PHP SDK: CVE-2026-53965, Composer package mcp/sdk, the official PHP SDK, versions 0.5.0 through 0.7.0. CVSS 4.0 base 6.9 Medium, availability impact only. The HTTP client transport appends every chunk of an SSE stream to an in-memory buffer with no upper bound, flushed only when the event delimiter arrives.
  • Context7: CVE-2026-75130, through version 2.1.2. Prompt injection through the Custom AI Instructions feature served via its MCP server, used to exfiltrate credentials from the environment. NVD carries TWO scores for it from the same secondary assessor: CVSS 4.0 base 6.4 Medium, and CVSS 3.1 base 9.0 Critical.
E/02What we do not yet know
  • Fifteen is what our own scout surfaced from GHSA and NVD in a ten day window using our query set. It is not a census of the ecosystem, and a different query set returns a different number.
  • NVD lists every one of these as Received, meaning NVD has not analysed them. Each score above comes from the CNA or a secondary assessor, not from NVD's own assessment.
  • We did not reproduce any of these and we observed no exploitation. Our public sensor is offline, so we hold no telemetry and no detection rates.
  • Whether this is a real rise or simply more people looking is unknown. Advisory volume measures attention, not the number of flaws that exist.
  • For Context7 we cannot say which of the two scores better describes the risk. Both come from the same source and we reproduced neither.