Threat Research
Anthropic Won't Patch MCP at the Protocol Level. Here's What That Hands You.
Ox Security found an architectural RCE at the core of MCP — and Anthropic declined to fix it at the protocol level, calling it by design. That hands the problem to everyone building on MCP. Patching downstream is necessary but never complete; the missing layer is runtime containment on the agent-to-tool wire.
CheckedAgent
·
Key takeaways
Ox Security's 2026 research found an architectural RCE in MCP's STDIO transport — it executes any command it's handed, even on failed startup, across the official Python/TypeScript/Java/Rust SDKs ("execute first, validate never"). One root cause, at least ten CVEs.
The scale Ox reports: 150M+ downloads, 7,000+ exposed servers, up to ~200,000 vulnerable instances, and nine of eleven MCP registries poisoned in a distribution test.
Anthropic declined a protocol-level fix, calling the behaviour by design and advising caution — so the fix must be re-implemented by every SDK and downstream project, one at a time (e.g. LiteLLM's command allowlist, CVE-2026-30623).
Shift-left and per-project patches are necessary but incomplete: the next library or poisoned registry entry reopens the hole, and neither sees what a compromised server does at runtime.
Runtime containment — bidirectional inspection of the agent-to-tool wire, trust-on-first-use for tool-definition changes, tamper-evident logging — is the safety net for when an upstream control misses one. It does not replace patching the RCE; it contains the compromised server the broken supply chain lets through.
When a model provider tells you a remote-code-execution path is working as intended, that is not the end of a security story. It is the beginning of your part of it.
That is roughly where the Model Context Protocol ecosystem sits after Ox Security's spring 2026 research. Ox found that MCP's STDIO transport — the default way an agent launches a local tool — executes whatever command it is handed, with no boundary between configuration and execution, and it runs that command even when the server itself fails to start. One security researcher summarised the posture as "execute first, validate never." From that single root cause, present across the official Python, TypeScript, Java, and Rust SDKs, Ox derived at least ten Critical and High CVEs and demonstrated command execution on live production platforms. The blast radius they describe is a supply chain of more than 150 million downloads, over 7,000 publicly accessible servers, and — by their estimate — up to 200,000 vulnerable instances. In a marketplace-distribution test, they reported successfully poisoning nine of eleven MCP registries with a malicious trial package.
What makes the finding systemic rather than a single bug is the range of ways it surfaces. Ox groups the exploitation into four families: unauthenticated injection through the user interfaces of popular AI frameworks; bypasses of the hardening in environments that market themselves as protected; zero-click prompt injection reaching AI coding IDEs such as Windsurf and Cursor; and malicious distribution through the package marketplaces agents pull from. Different entry points, one root cause — which is precisely why patching any single door leaves the others open.
The most important line in the whole episode, though, is not a number. It is Anthropic's response. Presented with the finding, Anthropic confirmed the behaviour is expected — by design — and declined to change the protocol. It updated its security guidance to advise caution with STDIO adapters and left the execution model in place. There is a reasonable architectural argument behind that decision, which we will get to. But its practical effect is unambiguous: the responsibility for containing this class of risk has been handed, deliberately, to everyone building on MCP.
This post is about what that handoff means, and specifically about the layer that is left holding it.
"By design" is a decision, not a dismissal
It would be easy, and wrong, to frame Anthropic's response as negligence. A protocol that launches local processes has to run some command, and drawing the trust boundary at the integrator — "you decide what you execute" — is a defensible position for a low-level transport. Reasonable people can argue that the SDKs should ship a manifest-only mode or a command allowlist by default, and reasonable people at Anthropic have argued they should not. That debate is real and it is not the point of this post.
The point is what follows from the decision, whichever way you think it should have gone. Because the protocol will not change, the fix cannot come from one place. It has to be re-implemented, correctly, by every SDK, every framework, and every downstream project that touches MCP — one at a time. And that is exactly what is now happening.
Downstream patches prove the problem rather than solve it
Look at how the ecosystem is actually responding and you see the shape of the gap. LiteLLM, one of the affected projects (its issue tracked as CVE-2026-30623), shipped a fix: a command allowlist that restricts STDIO launches to a small set of known-good binaries and rejects anything else at request-parsing time. It is a good fix. It is also entirely local to LiteLLM. The next framework has to write its own; the one after that has to remember to; and a project that quietly forwards a command without that check reopens the same hole. When the root cause lives in a protocol that will not move, "patched" becomes a per-project property that has to be re-earned continuously, across an ecosystem of hundreds of independently maintained libraries.
One root cause, many CVEs — and because the protocol won't change, every patch is per-project, and the next poisoned entry reopens the hole.
Shift-left tooling helps here, and it should be used. Static analysis that flags an unsafe STDIO configuration at code-authoring time — the category Ox's own product works in — catches a real slice of this before it ships. But shift-left has a fixed horizon: it reasons about code as written, not about what a running agent does when a compromised or malicious server answers it at 3am with a poisoned tool definition or an exfiltration instruction. The nine-of-eleven poisoned-registry result is the tell. If a malicious package can reach a registry, then some fraction of agents will install it having passed every authoring-time check, and the only place left to catch it is at runtime, in what the server actually does once it is connected.
The layer that survives the next CVE
Here is the uncomfortable arithmetic of a broken-by-design supply chain: the tenth CVE in a family of ten will be followed by the eleventh in a family of eleven. You cannot patch your way to the end of a list that the protocol keeps regenerating. What you can do is add a layer that assumes an upstream control will eventually miss one, and contains the damage when it does.
That is the case for runtime containment, and it is where CheckedAgent operates. CheckedAgent is an inline Agent Detection and Response proxy that sits on the wire between an agent and the MCP servers it calls, inspecting the traffic in both directions and classifying every message ALLOW, QUARANTINE, or BLOCK in real time. It does not care whether a server arrived through a clean install or a poisoned registry entry; it watches what that server actually sends and asks for. A tool whose definition mutates after you first trusted it — the exact move a malicious marketplace package makes — is caught by trust-on-first-use tracking rather than waved through. A tool response carrying an injected instruction or an exfiltration URL is inspected on the way back, not just on the way out. And because the record of all of it is written to a tamper-evident audit trail, "what did the compromised server do" has an answer after the fact.
Walk the marketplace case through to see why the timing matters. An agent installs a tool from a registry that was, unknown to anyone, poisoned — one of the nine-in-eleven Ox reported reaching. Every authoring-time and install-time check passed, because at install time the tool looked fine. Later, in production, the tool's definition shifts, or one of its responses comes back carrying an instruction the agent was never meant to receive. There is no new commit to scan and no new deploy to gate; the change happens at runtime, on the wire, inside a tool you already approved. Something has to be watching there — after the install, during the conversation — or the compromise simply runs.
It is worth being precise about what this does and does not cover, because overclaiming would undercut the argument. Runtime containment does not prevent the underlying command-injection RCE that Ox found; that is an application-layer execution bug, and the place to fix it is the SDK or the downstream project, exactly as LiteLLM did. What runtime containment addresses is the layer above: the malicious or compromised MCP server that the broken supply chain lets through, and the things it tries to do to your agent once it is connected. Prevention of the RCE and containment of a compromised server are different jobs, and a serious platform needs both.
Defence in depth, not a turf war
The healthiest way to read the Ox research is not as a scoreboard of who detects which CVE. It is as a map of a defence-in-depth problem with a clearly missing layer. The model provider owns the protocol decision and has made it. The SDK and framework maintainers own the per-project fixes and are shipping them. Shift-left tooling owns the authoring-time catch and is doing its job. The layer with the fewest occupants is the runtime one — the place that assumes something upstream will eventually fail and is watching the agent-to-tool wire when it does. Each layer covers what the others cannot; none of them is sufficient alone.
Shift-left and SDK patches cover authoring and install. The poisoned server does its work at runtime — the layer only containment watches.
If you run MCP in production, the question the Ox research really puts to you is not "have we patched the CVEs" — you should, and you will, and more will come. It is: when a compromised server slips through the supply chain despite our best patching, what is watching what it does to our agents in real time? Anthropic has told you, in plain terms, that the protocol will not answer that question for you. That makes it yours to answer — and the honest answer, for most teams today, is that nothing is watching the wire at all.
CheckedAgent is an Agent Detection & Response (ADR) platform for MCP: an inline proxy that inspects JSON-RPC traffic between AI agents and their tools in both directions, classifying every message ALLOW / QUARANTINE / BLOCK in real time and recording it in a tamper-evident audit trail. It is a runtime-containment layer that complements shift-left tooling, SDK fixes, and identity controls; it does not replace them, and it is not a substitute for patching known vulnerabilities.
Sources
Every Agent action.
Checked.
30-minute walkthrough with a security engineer — not a sales rep. We'll show the full pipeline, run your suspected attack patterns through it, and answer the questions your auditor is already asking.