> status: mostly fine. patch anyway.practical AI security · est. 2026

Brief · Builders

Nine MCP servers, one mistake: your agent's tools are a shell prompt

By alkizz ·

On Oct 27, VulnCheck published nine CVEs against nine different MCP servers in about ten seconds, and if you squint, eight of them are the same bug. An agent calls a tool, the tool takes a parameter like a repo name, a file path or an email subject, and the server pastes that string straight into a shell command. If the string contains $(...) or backticks, the shell runs whatever is inside, with the permissions of whoever started the server, which is usually you.

The part worth sitting with is who writes that string. It isn't you, and it often isn't the model either, because it comes from whatever the agent was reading at the time. The VulnCheck record for the ATXP Gemini CLI extension spells it out: "Attackers can plant instructions in email or SMS content to inject $() or backtick substitutions into parameters like message_id, subject, or query, running commands as the user."

None of these are household names, nothing is known to be exploited, and only one has a fix. So this isn't a fire drill, but it is a decent excuse to look at what's actually plugged into your agents.

What's actually confirmed

The nine

CVE Server What reaches the shell Fix (as of Oct 28)
CVE-2026-117558 ai-sdlc MCP server (through 0.31.2) repo argument into gh issue view / gh pr view via execSync() Commit 717d7ec, released in plugin and @ai-sdlc/plugin-mcp-server 0.32.0 (Oct 27)
CVE-2026-117559 DroidMind (through 0.4.0) $(...) or backticks slip past its shell allowlist, so blocked commands like reboot run on connected Android devices None named
CVE-2026-117560 ATXP Gemini CLI extension (through 1.0.0) message_id, subject, query and other tool parameters None named
CVE-2026-117561 sf-mcp (through 1.3.2) Salesforce CLI flag values, because its escapeValue() helper doesn't neutralize backticks or $() None named
CVE-2026-117567 esp-mcp (through commit 28afddf) target, port, project_path, project_name via asyncio.create_subprocess_shell None named
CVE-2026-117568 mcp-ffmpeg (through 1.0.5) videoPath and outputDir, so the payload can sit in an existing file or folder name None named
CVE-2026-117569 Kali-GPT (through commit a608c74) Scanner parameters like target, ports, domain, url via subprocess.run(shell=True) None named
CVE-2026-117570 nmap-mcp (through commit 3636afa) Not injection: a permissive NSE script allowlist (CWE-183), scored 4.8 None named
CVE-2026-117573 hagent (through commit 761eec6) args to its Arduino and ESP32 tools via subprocess.run(shell=True) None named

Scores are 8.5 (CVSS 4.0) for seven of them, 7.3 for mcp-ffmpeg and 4.8 for nmap-mcp, per the CVE records.

The lesson isn't these nine

DroidMind had a shell allowlist and sf-mcp had an escape helper, and both still lost to $() or backticks, which tells you something about bolting a filter onto a shell. ThreatAft's practical point is the one I'd keep: treat any MCP server that shells out as having this defect until someone reads the code, because the check is a code search, not a CVE lookup. The patterns to grep for are shell=True, create_subprocess_shell, execSync and child_process.exec, and the safe version passes an argument array (execFile in Node, a list without shell=True in Python) so there's no shell to inject into. That's exactly what the ai-sdlc fix did.

It's also the same story as the approval prompt nobody was watching: the dangerous part of an agent is rarely the model, it's the plumbing that turns text into actions.

Meanwhile, in OpenHands

A separate VulnCheck CVE from Oct 26 is the more serious one if you use it. CVE-2026-112346 says the OpenHands Software Agent SDK's DockerWorkspace and Apptainer launchers, before 1.52.0, bound the sandbox agent server to all network interfaces with an empty session_api_keys list, so "Attackers who can reach the published container port can send unauthenticated HTTP and WebSocket requests to execute arbitrary shell commands as root in the sandbox, access the mounted workspace, and read plaintext secrets from the secrets store." It's scored 9.3 (CVSS 4.0) and network-reachable, which is a different league from the nine above.

The good news is the fix is old news: version 1.52.0 shipped Oct 5, and only the disclosure is new. The fix (PR #5209) publishes the DockerWorkspace ports on the host's loopback address instead of every interface. The PR and the release notes only mention DockerWorkspace. The Apptainer launcher's code didn't change in 1.52.0 and still starts the agent server on 0.0.0.0. If you use Apptainer, don't count on the upgrade alone: set a session API key. It's also not in KEV, and the CVE record keeps the damage inside the sandbox: root in the container, the mounted workspace and the secrets store, not the host itself. That's still your workspace and your secrets, though.

The score

I'd call it a 3, patch normally. The bug class is real and the scoring hides it, but these are small projects, nothing is in KEV and nobody has reported exploitation. If you run one of the nine, or an OpenHands SDK older than 1.52.0 (or its Apptainer launcher without a session API key) on a shared network, treat your own copy as more urgent than the score.

What to do:

Sources

← All briefs