Skip to main content

Command Blacklist Bypass in hdresearch/mcp-shell (CVE-2026-78811)

· 4 min read
Bandana Kaur
APISec Research Labs

mcp-shell is an MCP server that lets an AI client such as Claude Desktop run shell commands. It advertises "secure command execution" through a blacklist of dangerous commands. The blacklist checks only the first word of the command, and then the entire string is handed to a shell. Anything after a ; runs unchecked.

CVE: CVE-2026-78811 · Severity: High (CVSS 4.0: 8.5 · CVSS 3.1: 7.8) · CWE: CWE-78, OS Command Injection · Affected: hdresearch/mcp-shell run_command MCP tool, all commits through e522726b533d46ee442e5710bf0ba46ad6142945 (December 15, 2025). No tagged releases. No fix known — repository HEAD is still e522726 as of October 28, 2026.

What Goes Wrong​

The run_command handler in src/index.ts does the following:

const command = request.params.arguments?.command as string;
const baseCommand = command.trim().split(/\s+/)[0];
if (!(await commandExists(baseCommand))) {
throw new Error(`Command not found: ${baseCommand}`);
}
if (!validateCommand(baseCommand)) {
throw new Error(`Command not allowed: ${baseCommand}`);
}
const { stdout, stderr } = await execa(command, [], {
shell: true,
env: process.env,
});

validateCommand only asks whether that first word is in a set of 20 or so names (rm, rmdir, sudo, dd, and similar). The full string then runs with shell: true, so ;, &&, |, $() and backticks are all live. The first word decides whether the command is allowed, and the rest runs unchecked.

They say the first impression is the most lasting. This blacklist took that to heart: it reads the first word, forms its opinion, and never looks again. Everything after the semicolon gets in on the strength of a polite ls.

Proof of Concept​

This is the same harmless command reported in the public issue (hdresearch/mcp-shell#17):

ls ; rmdir TEST_TO_REMOVE

ls passes the check. rmdir is on the blacklist, but it never reaches it, so the directory is removed.

Even Without Metacharacters, the Blacklist Is Thin​

The list does not include sh, bash, python, curl, mv or many other commands, so a blacklisted action can usually be done another way. Patching the shell injection alone would not make the tool safe to expose to untrusted input.

Impact​

Arbitrary command execution as the user running the MCP server: file changes or deletion, reading data, and anything else that user can do. The server runs over stdio under an MCP client, so the attacker is whoever controls the command argument. That could be a malicious or compromised client, another MCP server in the same session, or content that steers an AI agent into making a crafted call (prompt injection through a web page, document, or tool output). Users who treat the blacklist as a safety boundary are the ones exposed.

What To Do​

No patched version exists. Until one does:

  • Don't run mcp-shell against untrusted content, documents, or other MCP servers.
  • Run it in a container or VM with no credentials mounted.
  • Require human approval for every tool call, and read the command before approving.

For maintainers:

  • Run commands without a shell: pass the executable and an argument array to execa.
  • Replace the blacklist with an allowlist of permitted executables, with validated arguments.
  • Or document the tool plainly as unsafe, and remove the "secure" claims from the README.

Disclosure Timeline​

DateEvent
Jan 28, 2026Reported publicly as hdresearch/mcp-shell#17, since the repository has no SECURITY.md or private contact
Jun 13, 2026CVE requested from MITRE
Sep 2, 2026CVE-2026-78811 assigned
Oct 28, 2026Repository HEAD still e522726; no fix committed. Advisory published

References​

The Big Picture​

MCP servers often get the same first-impression treatment from the teams that install them. One look at the README, one line in a config file, and no second glance while the server runs with a developer's full privileges.

mcp-audit gives security teams visibility into which MCP servers are connected across developer machines, what tools they expose, and where the risk is. A tool called run_command should show up in your inventory before it shows up in a CVE.

Credit​

Discovered and reported by Bandana (HackWitHer), APIsec Research Labs.