Blacksec

Administrator
Staff member
ROOT
VIP
Hey hackers - the mcp supply chain of 2026 is one STDIO interface, ten CVEs, and a protocol vendor calling arbitrary command execution expected behavior.
An mcp supply chain attack in 2026 does not need a memory corruption bug - it needs a JSON field called command, an argument called args, and a client that treats configuration as code.
TL;DR: OX Security's April 2026 advisory mapped four vulnerability families across Anthropic's official MCP SDKs - unsafe STDIO defaults reaching 7,000-plus public servers and 150 million downloads - with CVEs against LiteLLM (CVE-2026-30623), Upsonic's allowlist bypass through npm argument flags (CVE-2026-30625), Windsurf's zero-click prompt-injection-to-RCE (CVE-2026-30615), and DocsGPT's hidden STDIO trigger (CVE-2026-26015).
Tool poisoning matured from Invariant Labs' April 2025 proof-of-concept into the Miasma worm's 73 poisoned GitHub repositories in June 2026, while TrustFall showed Claude Code, Cursor CLI, Gemini CLI, and Copilot CLI all auto-executing project MCP servers on a single folder-trust keypress.
The neighbors: trojanized downloads, payload delivery, agent tooling.

One protocol, four families​

The root cause OX Security identified is architectural: the MCP SDK's STDIO transport exists to spawn a local server process, and the command field runs whatever it is given. When a JSON configuration says command is rm and args are flags that delete something, the SDK executes it before it can fail to become a server - errors return after the command already ran.
Four families follow from that one design: unauthenticated command injection through plain STDIO configurations; authenticated injection that bypasses hardening by smuggling execution through allowlisted binaries - Upsonic permitted npm and npx, and npm takes flags that run arbitrary commands.
The remaining two need no credentials at all. Zero-click injection has an attacker's HTML rewrite the local MCP configuration through the agent's own prompt processing, which is the Windsurf CVE. Hidden STDIO triggers sit behind a GUI that shows only SSE and HTTP transports while the backend still parses STDIO - swap the transport in transit, add a command field, and DocsGPT's production servers execute it. Same root, four doors, none of them locked by default.
Ten-plus product CVEs share the same root - GPT Researcher, Fay Framework, Langchain-Chatchat, Flowise, Jaaz, LibreChat, WeKnora, MCP Inspector, Cursor - reported independently over two years and unified only when someone read the SDK. Anthropic declined to change the architecture, classifying the behavior as expected for a local-server launcher, which means every downstream implementation inherits the decision. Shifting responsibility to implementers does not transfer the risk; it obscures who created it.
FamilyRepresentative CVEDelivery
Plain STDIO injectionCVE-2026-30623 (LiteLLM)authenticated config UI
Allowlist bypassCVE-2026-30625 (Upsonic)npm/npx argument flags
Zero-click prompt rewriteCVE-2026-30615 (Windsurf)attacker HTML in agent context
Hidden network triggerCVE-2026-26015 (DocsGPT)transport-type swap in transit
Transport library RCECVE-2025-6514 (mcp-remote)authorization URL to shell, CVSS 9.6

The poisoning catalog​

Tool poisoning attacks the metadata layer instead of the process. Invariant Labs' April 2025 proof-of-concept hid instructions in a tool description - invisible to the user's review UI, perfectly legible to the model - and the agent read the user's mcp.json, then SSH private keys, and shipped them through a benign-looking parameter while narrating arithmetic to the operator.
Three variants hardened into the catalog: description poisoning at connect time, rug pulls that swap the description after approval, and tool shadowing, where one malicious server rewrites the agent's behavior toward a trusted server's tools so credentials cross into hostile hands. The protocol has no attestation for any of the three - no signature on descriptions, no re-verification after connect, no boundary between servers sharing one context.
The IDE layer turned approvals into theater. Cursor's MCPoison (CVE-2025-54136, CVSS 8.8) bound approval to the server's name rather than its content - commit an innocent configuration, wait for the team to approve it, replace the command, everyone executes silently. CurXecute (CVE-2025-54135, CVSS 8.6) used a Slack message to rewrite the global configuration file, and auto-execution ran it on the next interaction.
Benchmarks across 45 real-world servers recorded success rates over 60 percent, with the strongest agent model reaching 72.8 - and every one of those successes was an mcp supply chain event wearing a tool review dialog as a disguise.
Hash every configuration file. mcp.json and equivalents in version control, diffed on commit - approval binds to the hash, not the name, and a changed file is a new decision.
Disable auto-execution. Folder-trust prompts must not imply process spawn; if the client will not separate them, remove project-level servers from anything that opens untrusted repositories.
Scan descriptions as code. Signed manifests, embedded-instruction detection on description and schema changes, re-review on every server version bump - Microsoft's June 2026 guidance treats tool descriptions as supply-chain assets because they are.
Watch the worm pattern. Miasma planted configurations across 73 repositories including azure/durabletask - audit any workspace whose .mcp.json or IDE config files you did not author yourself.

The one-keypress problem​

Adversa AI's TrustFall disclosure in May 2026 generalized what Cursor showed in fragments: Claude Code, Cursor CLI, Gemini CLI, and GitHub Copilot CLI all auto-executed project-defined MCP servers after the folder-trust prompt, without disclosing that acceptance meant process spawn, and all four defaulted the prompt to yes. One Enter keypress in a malicious repository spawned an attacker's process with the developer's full OS privileges.
Claude Code's headless mode - the default for the official pull-request action - skipped the dialog entirely, so the same repository hit CI with zero human interaction. The pattern generalizes past IDEs: any workflow that auto-trusts a repository's local configuration on first open inherits the one-keypress problem, CI runners included.
Amazon Q extended the pattern to cloud credentials. Wiz Research's June 2026 disclosure (CVE-2026-12957, CVE-2026-12958) showed a crafted .amazonq/mcp.json workspace file loading without consent or workspace trust, spawning a server whose environment inherited AWS keys, CLI tokens, and SSH agent sockets - arbitrary code execution plus immediate cloud access from one cloned folder. Any mcp supply chain defense that stops at the workstation misses the part where the workstation's workload identity walks out with the payload.
The structural fix is boring: configuration changes are privileged operations. Re-prompt on diff, not on name; treat a workspace file containing a command field exactly like a Makefile you were asked to run - because that is what it is. The mcp supply chain stays this weak for as long as a JSON edit counts as a settings tweak.

Worms, packages, and registries​

The Miasma campaign in June 2026 - attributed to TeamPCP/UNC6780 - planted adversarial MCP configuration files across 73 GitHub repositories, among them Microsoft's azure/durabletask project. Developers who opened an affected repository in a vulnerable IDE executed credential-harvesting code with no warning: a single compromised repository propagating execution to everyone who clones it, indistinguishable from normal project setup in review.
The worm wrote configurations; the configurations spawned processes; the processes harvested credentials that opened the next repository. Supply chains do not need package registries when git itself carries the payload - and the campaign's only real requirement was that victims open their own work in their own tools.
Package registries supply the quieter route. postmark-mcp, published to npm in September 2025 as a legitimate email integration, blind-copied every outbound message to an attacker's address for weeks before anyone noticed - the first confirmed malicious MCP server on a public registry, but not the last shape: by early 2026, scanners were indexing exposed MCP endpoints leaking credentials and conversation data directly.
SPECTER MCP-POISON formalized the registry as a target, cataloging CVE-2026-52869 (Python SDK authentication bypass, 7.6) and CVE-2026-58500 (Appium XSS-to-RCE, 8.2) as the supply chain's opening moves. When the catalog of attack tools names your package registry, the registry has stopped being plumbing and started being an attack surface with an audience.

What detection can see​

Three signals separate an MCP estate under attack from a busy one. First, configuration drift: mcp.json and IDE config files changing outside human commits - hash the files in review and alert on mismatch. Second, process lineage: a server process spawned by an IDE whose parent chain crosses a clone-and-open event, particularly with network listeners or outbound calls to fresh domains. Third, description mutation: tool metadata changing between sessions, the rug-pull signature, caught by pinning descriptions and diffing at connect time.
Together the three cover the mcp supply chain at the only layer where defense still works: before the command field executes. Packet-level visibility catches the rest. STDIO attacks leave no network trace - they run locally - so the local signals above carry that family; the network-triggered family shows up as transport-type anomalies and configuration writes arriving over HTTP where the GUI promised SSE only.
A SOC that already watches for suspicious child processes from developer tools needs only the spawn rules and the diff rules to cover most of the catalog; what it usually lacks is anyone treating IDE configuration as an event source at all. Add that source and the catalog shrinks to whatever nobody has an alert for yet.

Defending an MCP estate​

Inventory first: every server, its transport, who approved it, and what it can reach. Most teams discover project-level servers nobody remembers adding, because a folder-trust prompt was a speed bump on the way to a tutorial. An mcp supply chain program starts with that list and never lets it go stale. Once inventoried, the controls split cleanly. Configuration: hash-pinned files in review, approval bound to content, auto-execution disabled, command fields treated like shell scripts.
Runtime: servers spawned with stripped credentials, network egress allowlisted per server rather than shared, and STDIO configurations blocked entirely on anything network-exposed - the transport that exists to launch local processes has no business listening publicly. Descriptions and schemas scanned as supply-chain artifacts on every version bump, with re-review triggered by metadata change the way a dependency update triggers review.
Credentials harvested from one compromised IDE session remain valid everywhere - the same combo-list economy that monetizes browser cookies monetizes AWS keys and SSH agents from exactly these payloads. Isolation at spawn time is what turns a stolen session into a stolen empty session.
Process: spawn alerts on IDE-parented children with new listeners, outbound calls to first-seen domains, and bulk reads of .ssh, .aws, and credential stores - the collection pattern every documented payload performs before it exfiltrates.
Registry posture: pin exact versions, verify integrity hashes, and prefer servers you have read; with 7,000-plus public servers and no attestation requirement, the vetting program is yours to build because nobody upstream is building it. Budget for it accordingly - an mcp supply chain audit costs less than one harvested AWS key, and the key does not stop billing when you notice it.
LayerControlDefeats
Configurationhash-pinned review, diff-bound approvalMCPoison rug pulls, worm commits
Executionauto-run off, trust prompts split from spawnTrustFall, CurXecute, headless CI
Transportno public STDIO, network transports onlyfour OX families, hidden triggers
Metadatasigned manifests, description diffspoisoning, shadowing, registry swaps
Egressper-server allowlists, credential isolationexfil from poisoned tool responses

The stance that holds​

The mcp supply chain of 2026 is what happens when configuration becomes executable and approval tracks names instead of content: four vulnerability families from one STDIO decision, a worm writing configs into 73 trusted repositories, a registry economy with no attestation layer, and a protocol vendor calling the result expected.
What holds is treating every MCP artifact - configuration file, tool description, server package, spawned process - as a supply-chain object with an owner, a hash, and a review: pin the configuration, diff the metadata, isolate the spawn, strip the credentials, and alert on the child process. The protocol will not fix itself this year; Anthropic's position is on record. Everything between the JSON field and the network is yours, and the teams that ship that boundary before the next advisory will read it as confirmation instead of discovery.