Est.

STDIO Remote Code Execution in Local MCP Servers

Anthropic's foundational MCP design flaw turns local servers into code execution channels.

Staff Writer · · 9 min read
Cover illustration for “STDIO Remote Code Execution in Local MCP Servers”
AI Agent Attacks · September 22, 2026 · 9 min read · 2,071 words

The remote code execution problem inside MCP's STDIO transport is a design decision Anthropic made when it built the protocol. It's a design decision Anthropic made when it built the protocol, and it now sits underneath thousands of servers running in production right now. Fixing it means rethinking how local servers earn trust in the first place, because there's no patch coming.

Anthropic introduced MCP in November 2024, pitching it as the "USB-C of AI agents," a single standard that lets any AI system plug into any tool or data source without custom integration work for each pairing. The protocol defines two transport mechanisms. Streamable HTTP, which can optionally use Server-Sent Events, handles remote servers. STDIO, short for Standard Input/Output, handles local processes instead. It caught on fast because it skips networking entirely: the MCP client just launches the server as a subprocess and talks to it over standard input and output streams, the same pipes any command-line tool uses. Register a tool, point at a command, done. That low friction explains why STDIO became the default pattern for local integrations well before anyone wrote real security guidance for it.

The architectural decision that makes STDIO an execution channel

STDIO configuration looks almost boring on paper. A JSON or YAML file lists each server by name, gives the command used to launch it (something like npx some-mcp-server), and adds whatever arguments it needs. The SDK reads that command string and hands it straight to the operating system.

That handoff is the whole problem. The SDK runs the configured command with no check that it points to a real MCP server, no cleanup of what's inside the string, and no allowlist turned on by default. Whatever's written in that config file runs, exactly as written.

Worse, the order of operations runs backward. Validation, such as it exists, happens after execution starts, not before. A malicious command fires, runs its payload, and exits immediately, and the SDK only flags an error once it notices the subprocess didn't behave like a proper MCP server. By then the damage is already done. Execute first, ask questions never.

This isn't one vendor's mistake, either. The same execute-first pattern is visible across every officially supported SDK, in Python, TypeScript, Java, and Rust, because it was inherited from the SDK design. It's a shared architectural choice, made once at the protocol level, and every language binding built on top of it inherited that choice whether its maintainers knew it or not.

OX Security's April 2026 disclosure and the blast radius it revealed

OX Security spent five months on this before going public, starting research in November 2025 and publishing on April 15, 2026 under the title "The Mother of All AI Supply Chains." Five months is a long runway for responsible disclosure, and it tells you the researchers were mapping something bigger than a single vulnerable package.

The numbers back that up. OX estimated 150 million downloads tied to the affected supply chain, more than 7,000 publicly accessible servers exposed, and up to 200,000 vulnerable instances traced back to the same root design decision.

OX put it this way: "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." That's the entire disclosure in one sentence. One choice at the foundation, copied everywhere the foundation got reused, not a pile of unrelated bugs scattered across unrelated teams.

Four exploitation families: how the same design flaw surfaces across deployment contexts

Diagram: One Flaw, Four Attack Doors. Visualizes: Visualize four exploitation families that all trace back to the same STDIO execute-first design flaw.

Researchers have grouped the real-world attacks into four families. Each one walks through a different door, but they all exploit the exact same gap.

Unauthenticated command injection through web interfaces is the first. An attacker feeds malformed JSON through a public-facing UI for an AI framework, and that JSON ends up as a subprocess command. LangFlow and LiteLLM both demonstrated this vulnerability. In LiteLLM's case, the command field submitted during MCP server creation went straight into StdioServerParameters and ran as a subprocess on the proxy host, no questions asked. LiteLLM patched this in v1.83.6-nightly, with the first stable fix landing in v1.83.7-stable, adding a command allowlist (MCP_STDIO_ALLOWED_COMMANDS, covering npx, uvx, python, python3, node, docker, deno) plus validation at the data layer.

Allowlist bypass through argument injection is the second, and it's the one that should worry security teams the most, because it looks like a fix and isn't. Locking down which commands can run (python, npm, npx) sounds reasonable, until someone notices the arguments passed to those commands were never checked. Something like npx -c <malicious_command> slides right past the allowlist while still running arbitrary code, since the allowlist only ever looked at the command name, never at what came after it. Flowise and Upsonic both demonstrated this. An allowlist on the executable name alone does nothing if the arguments are still wide open. Most allowlists deployed today are giving teams a false sense of security.

Zero-click prompt injection in developer IDEs is the third, and it doesn't need the developer to do anything wrong. Malicious content, HTML embedded in a file someone opens, can quietly modify a local MCP configuration file. CVE-2025-54136, nicknamed "MCPoison," hit Cursor exactly this way. Cursor's trust model failed to re-verify server configuration contents after initial approval. Once a team member approved a project-level config, anyone could swap in a malicious command later, and Cursor would treat it as already trusted. No new prompt, no new approval. That turns a shared repository config into a direct attack vector for an entire team, not just one machine.

Malicious marketplaces and hidden STDIO configs round out the fourth. A bad actor lists a poisoned server on a public registry. A developer installs it, the client fetches the STDIO config, and it runs with no validation step anywhere in between. This is the clearest supply-chain angle of the four: the attack surface isn't the servers a team builds in-house, it's every registry entry anyone on the team might casually install on a Tuesday afternoon.

Confirmed CVEs: what the specific cases show about real-world exploitability

The families above aren't hypothetical patterns dreamed up in a lab. Specific CVEs put numbers and mechanisms behind them.

CVE-2025-6514, affecting mcp-remote, carries a CVSS score of 9.6, about as severe as it gets. The attack works through a malicious server sending back a weaponized authorization_endpoint value, which mcp-remote passes to the npm open() package. On Windows, that value gets executed through PowerShell, which evaluates an injected subexpression operator embedded in the URL, letting researchers bypass standard URL encoding. Full remote code execution on the client's operating system follows from there. More than 437,000 downloaded environments were affected, and the fix landed in mcp-remote version 0.1.16.

CVE-2025-49596 hit the official MCP Inspector, the dev tool teams use to test and debug their own MCP servers. It shipped with no authentication on its local web UI, so any webpage a developer happened to visit while Inspector was running could send a crafted request and execute code on that developer's machine. A debugging tool became an open door, which is about as close to irony as security research gets.

CVE-2025-54136 is the MCPoison Cursor case described above. CVE-2026-30623 covers the LiteLLM flaw: RCE through MCP server creation, the command field passed to StdioServerParameters with no validation, patched in v1.83.7-stable.

Four different products, four different teams, one repeated pattern. A command string travels from user input to OS execution with nothing meaningful checking it anywhere along the way.

Why STDIO RCE compounds with MCP's broader trust architecture

Diagram: The Credential Gap Beneath STDIO Risk. Visualizes: Show the authentication breakdown across public MCP servers that compounds STDIO's execution exposure: only 8.5% use OAuth, while 53% rely on static API keys or personal access tokens…

STDIO's execution gap doesn't sit in isolation. It compounds with weaknesses elsewhere in how MCP handles trust, and each weakness makes the others worse.

Authentication across the ecosystem is thin, and the numbers say so directly. A credential audit of public MCP servers found only 8.5% used OAuth, while 53%, more than half, relied on static API keys or personal access tokens, often passed through environment variables sitting right next to the process. That matters directly for STDIO risk: once an attacker gets command execution, the credentials sitting nearby are, in most cases, weak static secrets with no rotation and no scoping, rather than anything that would actually contain the damage.

Tool poisoning adds another layer on top. MCP tool description fields aren't sanitized, so a compromised or malicious server can bury arbitrary instructions inside what looks like ordinary help text. The model reading that description has no way to tell legitimate metadata from an injected instruction. That's a separate attack path from STDIO execution, but it can trigger STDIO commands indirectly, through the model itself. The two flaws feed each other.

Confused-deputy risk follows the same shape. An MCP server holding broad, ambient permissions, with no per-action check, gets steered into unauthorized actions just by manipulating what feeds into the model. The attacker never has to authenticate directly. They just have to influence the input, and the server does the rest of the work for them.

Stack a handful of MCP servers together in one deployment, which is the norm now rather than the exception, and a compromise in one server cascades into the others.

What "by design" means for enterprise governance and who owns the risk

Anthropic treats STDIO's execute-first behavior as expected, and that stance quietly turns a protocol-level defect into a pile of individual liability. Every team that adopts MCP has to notice this on its own, understand it on its own, and build its own defense, because the foundation itself isn't going to change shape to accommodate them.

That's landing on a lot of teams at once. Team8's CISO Village Survey found 70% of enterprises already running AI agents in production, and separate research suggests only around 23% of organizations have even a formal AI-agent identity strategy in place. Most of that growth sits on infrastructure that inherits the exact STDIO execution model described above, and the team building it out often has no idea.

Security teams cannot see a good chunk of what's running, either. Research has found that the majority of MCP servers run locally on developer machines, outside the normal channels IT or platform teams use to track deployed software, invisible to security teams by default rather than by neglect. That's shadow infrastructure by default, not by neglect. Developers spin up local MCP servers the same casual way they'd install any dev tool, and nobody upstream ever sees it happen.

Independent scans of public MCP servers run between 30% and 82% showing some form of vulnerability, depending on methodology. That range is wide because scanning approaches vary a lot between research teams, but no scan anywhere has come back and called the ecosystem clean. The range moves. The conclusion doesn't move with it.

Practical mitigations that address the architectural root cause

Patching individual CVEs treats symptoms, not the disease. Fixing the actual problem means treating every STDIO command parameter as untrusted input, full stop, the same way a competent web application treats user-submitted form data.

Start at the configuration layer. Every STDIO server definition in an environment needs an audit, and every command field inside those definitions needs to be read as a potential execution surface, not a harmless string someone typed once and forgot about. MCP server registration should run through an explicit, reviewed allowlist that blocks anything not already approved, rather than trusting whatever shows up in a config file that day.

An allowlist on command names alone won't hold, though, as the Flowise and Upsonic bypass cases already proved beyond argument. Argument-level checks matter just as much as command-level ones. npx sitting on an allowlist means nothing if -c <anything> slides through unchecked right behind it.

Trust approval needs to bind to content, not to a label. Cursor's MCPoison flaw existed because approval was tied to a config key's name, and once that name got approved, the contents behind it could change freely without ever triggering a new check. Any system granting persistent trust to an MCP server config needs to re-verify the actual contents every single time that config changes, not just the first time.

None of this closes the gap on its own. STDIO's execute-first design is still sitting in every SDK, in every language, on every machine running it right now. Enterprise governance has to treat that as a permanent constraint, and build controls around it accordingly, rather than waiting for a fix that isn't coming.

Sources

  1. Security Update: CVE-2026-30623 — Command Injection via Anthropic's MCP SDK | liteLLM
  2. Anthropic MCP Design Vulnerability Enables RCE, Threatening AI Supply Chain
  3. MCP by Design: RCE Across the AI Agent Ecosystem
  4. MCP Security Statistics 2026: CVEs, Vulnerabilities & Breach Data - Practical DevSecOps
  5. MCP Security Testing 2026: Model Context Protocol Risks
  6. The Mother of All AI Supply Chains: Critical, Systemic Vulnerability at the Core of Anthropic's MCP
  7. oligo.security
Filed underAI Agent Attacks

More in AI Agent Attacks