MCP Security Advisory — Systemic

The Mother of All AI Supply Chains: MCP's By-Design RCE

OX Security disclosed a systemic, by-design flaw in Anthropic's Model Context Protocol: passing a configuration string to the STDIO transport is passing a shell command. Anthropic's response was one word — expected.

Published April 21, 2026 / 10 CVEs · ~200K vulnerable instances / Interactive
In Plain English — Four Points
150M+
SDK Downloads
~200K
Vulnerable Instances
10
CVEs Assigned
4
Attack Families

One Design Decision, Every Language, Every Downstream Library

On April 15, 2026, OX Security Research published what they called "the mother of all AI supply chains" — a class of vulnerability baked into the reference implementation of the Model Context Protocol across every supported language. It is not a coding bug. It is the STDIO transport working exactly as specified.

The mechanics are brutally simple. When an MCP client spins up a local STDIO server, it accepts a command string and hands it straight to the operating system. If the command successfully spins up an STDIO server, you get a protocol handle. If it fails, you get an error — and the command still runs. Sanitization, allowlisting, warning signals: none of it is part of the protocol. The vulnerability is that the configuration format is the execution format.

Blast radius

OX confirmed live command execution on six production platforms — including LiteLLM, LangChain, and IBM's LangFlow. They also seeded a benign payload into 9 of 11 MCP marketplaces to prove malicious distribution trivially works. 150M+ SDK downloads; 7,000+ publicly exposed servers; up to 200K total vulnerable instances.

Anthropic was contacted on January 7, 2026. Their response, repeated across multiple rounds: the behavior is "expected," their execution model is a "secure standard," and hardening is the implementer's job. No protocol-level patch. No deprecation path. They did not object to public disclosure.

How an Error Return Is Actually a Shell Execution

The failure mode is counterintuitive: the error path is the attack path. Walk the flow node by node — each click reveals what happens at that step and why error-handling doesn't save you.

Interactive · StdioServerParameters execution path
Click or hover any node The error is emitted after execution No sanitization at any stage
Python SDK — the pattern being inheritedmcp.client.stdio
from mcp.client.stdio import stdio_client, StdioServerParameters

# Every field below flows directly to subprocess execution.
# User-controlled input here == remote command execution.
params = StdioServerParameters(
    command="npx",          # ← attacker-controlled in many deployments
    args=["-y", "some-mcp-server", "--flag"],
    env={"SECRET": "..."},
)

async with stdio_client(params) as (read, write):
    ...

The shape is identical in every SDK. TypeScript's StdioClientTransport, Java's StdioServerTransport, Rust's TokioChildProcess — all wrap an OS-level spawn of a caller-supplied command. Any component upstream that lets a model, a UI form, or a config file populate that string is an RCE primitive.

"Pass in a malicious command, receive an error — and the command still runs. No sanitization warnings. No red flags in the developer toolchain. Nothing." — OX Security Research Team

Four Families, One Root Cause

The same underlying pattern manifests in four distinct exploitation classes, each targeting a different layer of the stack. What makes this a supply chain event rather than a single CVE is that none of these vendors wrote the bug — they inherited the default.

Family 01

Unauthenticated UI Injection

Web dashboards in Agent Zero, Langchain-Chatchat, Jaaz, and others accept an MCP config via an unauthenticated form. The command string is saved, executed on first connect, and runs under the framework's identity.

Family 02

Hardening Bypass

Platforms that attempted a defense — e.g. Flowise's allowlist of npx/uvx — get bypassed with hostile arguments. npx -c "curl … | sh" is still npx. The allowlist guards the binary name; argv is unrestricted.

Family 03

Zero-Click Prompt Injection

In AI IDEs (Windsurf, Cursor), the agent can write to its own mcp.json. A poisoned README, web page, or file opened in the editor injects a prompt that tells the agent to append a malicious STDIO entry. Next reload → local RCE.

Family 04

Poisoned Marketplaces

OX submitted a benign proof-of-concept to 11 public MCP registries; 9 accepted it. MCP servers ship as text blobs carrying a command — closer to an install script than a package. No sandbox, no capability model, no signature baseline.

Six Months of Disclosure, Three Layers of Silence

Below is an interactive version of the disclosure timeline. Three horizontal swim lanes: the Root Layer (Anthropic itself), the Transport Layer (frameworks like LangChain, LiteLLM, FastMCP), and the Application Layer (end tools like Cursor, Windsurf, DocsGPT). Filter a layer to isolate it — the pattern across the stack is the whole story.

MCP Disclosure Timeline · Nov 2025 → Apr 2026
Nov '25
Dec '25
Jan '26
Feb '26
Mar '26
Apr '26
RootAnthropic
Jan 7 Anthropic contacted → "by design"
Jan 16 Anthropic updates SECURITY.md
Feb 13 Anthropic approves public disclosure
Apr 15 Public disclosure: "The Mother of All Supply Chains"
TransportFrameworks
Dec 31 LangChain contacted → "by design"
Jan 12 FastMCP, Flowise, Upsonic contacted
Jan 13 Gemini-CLI → "duplicate, no CVE"
Jan 19 LiteLLM contacted
Jan 22 Browser-Use → "by design"
Feb 6 Flowise & Upsonic patched
Feb 10 FastMCP → "by design"
Mar 17 CVE-2026-30623 (LiteLLM), CVE-2026-30625 (Upsonic)
ApplicationEnd Tools
Nov 9 GPT-Researcher contacted
Dec 25 CVE-2025-65720 (GPT-Researcher)
Jan 11 LangFlow + 3 undisclosed contacted
Jan 13 Claude Code, Cursor, Windsurf contacted
Jan 19 GitHub Copilot → "not a security vulnerability"
Feb 2 DocsGPT confirms fix
Feb 11 CVE-2026-26015 (DocsGPT)
Feb 23 Cursor rejects report
Mar 17 6 CVEs assigned: Windsurf, Jaaz, Langchain-Chatchat, Fay, Agent-Zero
Mar 18 CVE-2026-33224 (Bisheng)
› click a layer filter to isolate · scroll horizontally on small screens
What the shape tells you

Several weeks of individual "by design" responses at the root and transport layers, then a coordinated March 17 CVE burst at the application layer. The protocol owner did not move. The downstream projects — each absorbing the risk individually — had to.

The 10 CVEs That Came From One Protocol

Filter by status to see which projects moved and which are still sitting on a reported advisory. Every row traces back to the same STDIO pattern.

CVE Project Vector Severity Status
CVE-2025-65720 GPT Researcher UI injection / reverse shell Critical Reported
CVE-2026-30623 LiteLLM Authenticated RCE via JSON config Critical Patched
CVE-2026-30624 Agent Zero Unauthenticated UI injection Critical Reported
CVE-2026-30618 Fay Framework Unauthenticated Web-GUI RCE Critical Reported
CVE-2026-33224 Bisheng Authenticated UI injection (open registration) Critical Patched
CVE-2026-30617 Langchain-Chatchat Unauthenticated UI injection Critical Reported
CVE-2026-33224 Jaaz Unauthenticated UI injection Critical Reported
CVE-2026-30625 Upsonic Allowlist bypass via npx/npm args High Warning
CVE-2026-30615 Windsurf Zero-click prompt injection → local RCE Critical Reported
CVE-2026-26015 DocsGPT MITM transport-type substitution Critical Patched
CVE-2026-40933 Flowise Allowlist bypass / argv injection Critical Reported
Prior art — this class of bug is not new

The same root cause has been filed independently many times: CVE-2025-49596 (MCP Inspector), CVE-2026-22252 (LibreChat), CVE-2026-22688 (WeKnora), CVE-2025-54994 (@akoskm/create-mcp-server-stdio), CVE-2025-54136 (Cursor). Each landed on a different vendor's queue — because at the protocol level, nobody owns it.

"Expected Behavior" vs. Secure by Design

Anthropic's position is defensible on narrow technical grounds: STDIO MCP is a local transport, and a local transport that runs a binary you passed it is, in one sense, doing what it says on the tin. The problem is what happens when that transport's configuration format becomes reachable by untrusted inputs — model outputs, web UIs, marketplace payloads, repo files an IDE agent reads.

Every one of the four attack families above is a variation on the same theme: something upstream of StdioServerParameters got closer to untrusted than the protocol assumed. Shifting that boundary is exactly what a "secure by default" transport would do — command as an opaque executable reference, args as an allowlisted whitelist, a capability manifest shipped with each server. None of that exists.

"What made this a supply chain event rather than a single CVE is that one architectural decision, made once, propagated silently into every language, every downstream library, and every project that trusted the protocol to be what it appeared to be. Shifting responsibility to implementers does not transfer the risk. It just obscures who created it." — OX Security, "The Mother of All AI Supply Chains"

The disclosure landed days after Anthropic unveiled Claude Mythos, pitched as a tool to help secure the world's software. OX's framing is hard to miss: apply that same commitment to the protocol you own.

Remediation — Until the Protocol Moves

Because the vulnerability is architectural, there is no patch you can pull. Defense is about shrinking the distance between untrusted input and StdioServerParameters, and limiting blast radius when that boundary fails.

Control 01

Treat MCP Config as Code

Never let user input — including model output — flow into command or args. Use a fixed, pre-configured set of allowed MCP servers, stored outside any directory the agent can write.

Control 02

Sandbox Every MCP Server

Run each MCP process in a container with its own filesystem, no host keys, no cloud creds, no shell access. Docker MCP Toolkit and user-namespace isolation are both viable baselines.

Control 03

Block Public Exposure

LLM gateways and research tools with API keys and DB credentials should never have a public IP. The 7K publicly accessible MCP servers OX found are the low-hanging targets.

Control 04

Verified Sources Only

Pin to the official GitHub MCP Registry or a curated internal mirror. 9 of 11 public registries accepted a malicious payload — the long tail is untrusted by default.

Control 05

Log Every Tool Invocation

Treat MCP tool calls the way you'd treat exec(). Log command, args, env snapshot, and destination IPs. Alert on unexpected outbound traffic — exfiltration shows up there first.

Control 06

Upgrade the Patched Stack

LiteLLM, Bisheng, DocsGPT, Flowise, Upsonic have fixes. Upgrade everywhere (including CI runners and images). For unpatched vendors, disable the MCP integration or firewall the input path.

Immediate Action Checklist

The uncomfortable baseline

You cannot wait for the protocol to change. Assume every STDIO MCP entry on a machine is a potential exec surface, isolate those machines accordingly, and treat any UI or agent that can write MCP configuration as a privileged tool. The goal is containment, not prevention — with an architectural vulnerability, prevention is out of your hands.

The Protocol Owns the Ecosystem It Enables

Individual CVEs are footguns. A hundred CVEs tracing back to one line in one reference SDK is a policy choice. Anthropic's position — that implementers are responsible for the consequences of the default they inherit — is structurally similar to how every other insecure-by-default protocol in history was defended, right up until it wasn't.

MCP is the emergent standard for how AI agents communicate. Every company shipping an agent is, today, shipping on top of this default. The question is no longer whether the STDIO transport is dangerous — OX's ten CVEs settle that. The question is whether the protocol maintainers treat safe defaults as their job or as somebody else's. Until then, the ecosystem pays interest on a bug it did not write.