Skip to content

Don’t use shell=True in mcp dev subprocess on Windows (command injection risk) #1257

Open

Description

@0x-Professor

Initial Checks

Description

What’s happening:

When you run the mcp dev command on Windows, it starts another program using a method (subprocess.run with shell=True) that lets the Windows command prompt (cmd.exe) handle the command. This is risky because if any part of the command includes special characters (like &, |, %, etc.), Windows might run something you didn’t expect — even another program, if the file path or arguments are weirdly named or crafted.

Why this is a real problem:

  • This isn’t just a theory — it’s a well-known risk with shell=True in Python. If anyone (or any script) can control part of the file path or arguments, they might be able to run extra commands on your computer.
  • The Python documentation says to avoid shell=True when possible for exactly this reason.
  • The fix is easy: use shell=False and make sure the right Windows executable is picked (like npx.cmd).
  • This keeps things safe and works the same on all systems.

What should happen instead:

  • The command should be run without shell=True on Windows, just like it is on Linux/Mac.
  • File paths and arguments should always be passed as a list, not a single string.

How this could be abused:

  • If someone manages to sneak a file or argument with a shell special character into your project, running mcp dev could run extra commands (for example, opening Calculator if the file had &calc in its name).

Please fix:

  • Remove shell=True from the subprocess.run call in src/mcp/cli/cli.py (Windows part).
  • Make sure the command and its arguments are always passed as a list.
  • Make sure it works on Windows by using the right executable (like npx.cmd).

Thanks!

Example Code

# Example of risky situation on Windows:
# If a file is named "server&calc.py" and you run:
#   mcp dev path\to\server&calc.py
# Windows might run Calculator because of the &

# Please see src/mcp/cli/cli.py (mcp dev command) for the subprocess.run([npx_cmd, ...], shell=True, ...)

Python & MCP Python SDK

Python 3.11, Windows 11, latest MCP Python SDK (main branch, August 2025)

Activity

  1. added
    ready for workEnough information for someone to start working on
    P0Broken core functionality, security issues, critical missing feature
    and removed
    needs confirmationNeeds confirmation that the PR is actually required or needed.
    on Oct 6, 2025
  2. added
    P1Significant bug affecting many users, highly requested feature
    and removed
    P0Broken core functionality, security issues, critical missing feature
    on Feb 19, 2026
  3. Br1an67 commented on Mar 1, 2026

    @Br1an67

    I'd like to work on this. The fix removes shell=True from both subprocess.run calls—_get_npx_command() already resolves to npx.cmd/npx.exe on Windows, so shell dispatch is unnecessary.

    PR: #$(gh pr view --repo modelcontextprotocol/python-sdk --head Br1an67:fix/issue-1257-shell-injection --json number --jq '.number')

  4. added a commit that references this issue on Mar 26, 2026
    d199d49
  5. xr843 commented on Mar 26, 2026

    @xr843

    I'd like to work on this issue. Submitting a PR that:

    1. Replaces subprocess.run(..., shell=True) in _get_npx_command() with shutil.which() — safer and more efficient than spawning a shell just to check if npx exists
    2. Removes the conditional shell=True from the mcp dev subprocess call, since _get_npx_command() already resolves the correct executable (e.g. npx.cmd on Windows)
    3. Updates tests to match the new shutil.which() approach
  6. added
    triageQueued for automated analysis — bot will process and remove this label
    and removed
    triageQueued for automated analysis — bot will process and remove this label
    on Apr 24, 2026
  7. ghost added
    fix proposedBot has a verified fix diff in the comment
    on Apr 24, 2026
  8. ghost removed
    triageQueued for automated analysis — bot will process and remove this label
    on Apr 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Significant bug affecting many users, highly requested featurebugSomething isn't workingfix proposedBot has a verified fix diff in the commentready for workEnough information for someone to start working on

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions