Catching MCP Command Injection Before It Catches You: 3 Real CVEs, One Detection Demo
Bottom line up front: In the last two months, three real vulnerabilities in MCP servers were disclosed — a CrewAI stdio RCE (CVSS 9.8), a LiteLLM MCP-REST command injection (CVSS 8.7, actively exploited), and an Amazon Q Developer MCP auto-execution flaw (CVSS 8.5). All three share one root cause: MCP configs are executable, not data. This post walks through each CVE, then shows a working 40-line validator that catches this class of bug before it ships.
Why MCP configs are a trust boundary problem
Model Context Protocol (MCP) is how AI agents connect to tools — file systems, databases, browsers, your CI pipeline. The protocol's stdio transport is elegantly simple: your config file says "run python ./server.py" and the client does exactly that, as a subprocess on your machine, with your environment.
That design is the vulnerability. An MCP config is executable content, but nothing in the protocol treats it that way. There's no allowlist, no sandbox, no "is this config trustworthy?" checkpoint. A malicious repo, a typosquatted package, or a poisoned PR that drops an MCP config into your workspace is one step away from running arbitrary code with your credentials.
The three CVEs below are not hypotheticals. They are the pattern, disclosed in the wild.
CVE-2026-2287 — CrewAI MCP StdioTransport RCE (CVSS 9.8)
What it is: In CrewAI, StdioTransport.__init__() passes user-controlled command strings directly to stdio_client() with zero validation. Any MCP server config pointing at a malicious command triggers arbitrary OS process execution.
Why it matters: This is a mainstream agent framework — not an obscure tool. The vulnerability class is "Tool Injection": an LLM-generated tool_call parameter, or a poisoned config file, becomes an OS command with no intermediate check.
Status: Disclosed to MSRC (Case 126356), publicly tracked as CVE-2026-2287.
CVE-2026-42271 — LiteLLM MCP-REST command injection (CVSS 8.7, actively exploited)
What it is: LiteLLM's AI gateway exposed POST /mcp-rest/test/connection and POST /mcp-rest/test/tools/list — endpoints meant to preview an MCP server config before saving it. They accept the full config (including command, args, env) and, for stdio configs, spawn the supplied command as a subprocess on the proxy host with no sandboxing. CISA added this to the Known Exploited Vulnerabilities catalog on June 8, 2026 after active exploitation.
Worse: chained with CVE-2026-48710 (a Starlette Host-header bypass), it becomes unauthenticated RCE with a combined CVSS of 10.0 — no credentials required. Post-exploitation observed in the wild: web shell install, credential harvesting, lateral movement.
Status: Fixed in LiteLLM 1.83.7 (requires PROXY_ADMIN role for the test endpoints). If you run a LiteLLM gateway and haven't patched, this is a drop-everything upgrade.
CVE-2026-12957 — Amazon Q Developer MCP auto-execution (CVSS 8.5)
What it is: Language Servers for AWS (< 1.65.0) automatically loaded and executed MCP server configurations from .amazonq/mcp.json workspace files — no user consent, no workspace trust verification. Spawned processes inherited the developer's full environment, exposing AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, CLI auth tokens, API keys, and SSH agent sockets.
Why it matters: The attack surface isn't a network service — it's a developer's editor. A malicious PR, a typosquatted package, or a fake job-interview exercise drops a .amazonq/ config into the workspace, and Amazon Q runs it.
Status: Disclosed by Wiz Research (reported April 20, 2026; fixed in Language Servers 1.65.0 / Amazon Q 2.20).
The pattern behind all three
| CVE | Trigger | Executable element | Credential exposure |
|---|---|---|---|
| CVE-2026-2287 (CrewAI) | MCP config / tool_call |
command string → stdio_client()
|
full process env |
| CVE-2026-42271 (LiteLLM) | HTTP request to test endpoint |
command + args + env → subprocess |
all stored provider keys |
| CVE-2026-12957 (Amazon Q) | workspace .amazonq/mcp.json
|
auto-run command on open |
AWS credentials, SSH agent |
Every one is command-injection-adjacent, and every one is catchable with a config-time check that says: is this MCP config running a dangerous command, exposing secrets, or mixing stdio with env?
A working check: CCS MCPSecurityValidator
Here's the detection logic. It's real, it's open, and it runs in a small Python class. Install it:
pip install ccs-verifier
from ccs.guardrail import MCPSecurityValidator
malicious = {
"name": "file-ops-server",
"transport": "stdio",
"env": {"OPENAI_API_KEY": "sk-proj-***"},
"tools": [
{
"name": "purge_all",
"implementation": 'def purge_all():\n os.system("rm -rf /data/user/*")',
"env": {},
},
{
"name": "run_shell",
"implementation": 'subprocess.call(["bash", "-c", user_cmd])',
"env": {},
},
],
}
result = MCPSecurityValidator.validate_mcp_config(malicious)
print(result["safe"]) # False
Actual output against a config that mimics all three CVE patterns:
{
"safe": false,
"issues": [
{
"severity": "HIGH",
"type": "stdio_env_exposure",
"message": "stdio transport with env variables",
"cve_ref": "CVE-2026-12957",
"remediation": "Use env_isolation or switch to sse/http transport"
},
{
"severity": "CRITICAL",
"type": "command_injection",
"pattern": "rm -rf",
"cve_ref": "CVE-2026-42271"
},
{
"severity": "CRITICAL",
"type": "command_injection",
"pattern": "os.system",
"cve_ref": "CVE-2026-42271"
},
{
"severity": "CRITICAL",
"type": "command_injection",
"pattern": "subprocess.call",
"cve_ref": "CVE-2026-42271"
}
]
}
A clean config passes:
safe = {
"name": "reader",
"transport": "sse",
"env": {},
"tools": [{"name": "read", "implementation": "def read(): return open(f).read()", "env": {}}],
}
print(MCPSecurityValidator.validate_mcp_config(safe)["safe"]) # True
The validator flags:
-
command_injection —
rm -rf,curl | sh,wget | bash,eval(,exec(,os.system,subprocess.call(CVE-2026-42271 pattern) -
env_exposure —
API_KEY,SECRET,TOKEN,PASSWORD,PRIVATE_KEY,CREDENTIALS,AUTHin tool env - stdio_env_exposure — stdio transport shipping with env vars (CVE-2026-12957 pattern)
What the fix looks like in practice
These three CVEs were fixed in three different ways — but the pattern is the same everywhere:
-
Allowlist commands — never accept an arbitrary
commandfrom a config or untrusted caller. If you must, validate against an explicit allowlist (CrewAI's fix class). -
Separate privileges from config — stdio + env is the most dangerous combination. Use
env_isolation, or switch to SSE/HTTP with a narrow permission model (LiteLLM's fix class:PROXY_ADMINgating). - Explicit consent on auto-exec — never auto-run an MCP config that arrived with workspace content. Prompt, verify trust, then run (Amazon Q's fix class).
-
Verify at runtime too — config-time checks stop the obvious cases; a verification layer on tool output stops the rest. The MCP Python SDK defines a
readOnlyHinton tools, but the runtime never enforces it — our audit found this gap in 87 production code instances across six frameworks (AutoGen, Semantic Kernel, FastMCP, Dify, Griptape, MCP Python SDK).
Try it without installing anything
If you use Cursor or Claude Desktop, you can run a config check against any MCP server URL remotely:
https://mcp.correctover.com/mcp
Tools exposed: ccs_scan (scan a URL for MCP/runtime security issues), ccs_check (7-dimension runtime verification of tool output), ccs_info (CCS standard reference).
Or install locally: pip install ccs-verifier.
Correctover — Runtime Verification for AI agents. We research and disclose vulnerabilities in AI agent infrastructure (CVE-2026-2287, plus findings across 13 frameworks), and ship the tools to catch the next one before it ships.
CVE references verified against CISA KEV (June 2026), AWS Security Bulletin 2026-047, and MSRC Case 126356.
Top comments (0)