Skip to content

fix(security): remove shell=True to prevent command injection on Windows#2351

Open
xr843 wants to merge 1 commit intomodelcontextprotocol:mainfrom
xr843:fix/remove-shell-true-command-injection
Open

fix(security): remove shell=True to prevent command injection on Windows#2351
xr843 wants to merge 1 commit intomodelcontextprotocol:mainfrom
xr843:fix/remove-shell-true-command-injection

Conversation

@xr843
Copy link

@xr843 xr843 commented Mar 26, 2026

Summary

Fixes #1257 — removes shell=True from subprocess calls in mcp dev to prevent command injection on Windows.

  • _get_npx_command(): Replaced subprocess.run([cmd, "--version"], shell=True) with shutil.which(cmd) to locate the npx executable without spawning a shell. This is both safer (no shell metacharacter interpretation) and more efficient (no subprocess overhead just to check existence).
  • dev() command: Removed the conditional shell=True (shell = sys.platform == "win32") from the subprocess.run() call that launches the MCP Inspector. Since _get_npx_command() already resolves the platform-specific executable name (e.g. npx.cmd on Windows), shell dispatch is unnecessary.
  • Tests: Updated test_get_npx_windows and test_get_npx_returns_none_when_npx_missing to mock shutil.which instead of subprocess.run.

Why this matters

On Windows, shell=True passes commands through cmd.exe, which interprets shell metacharacters (&, |, %, etc.). If any part of the command string contains these characters (e.g. a crafted file path like server&calc.py), arbitrary commands could be executed. The Python documentation explicitly warns against this.

Test plan

  • Existing tests updated to reflect new shutil.which() approach
  • CI passes on all platforms
  • Manual verification: mcp dev server.py still launches the inspector correctly on Windows

🤖 Generated with Claude Code

Replaces shell=True subprocess calls with explicit argument lists to
prevent command injection vulnerabilities, particularly on Windows
where shell metacharacters can be exploited.

In _get_npx_command(), replaced subprocess.run() with shutil.which()
to locate the npx executable without spawning a shell process. This is
both safer and more efficient.

In dev(), removed the conditional shell=True for Windows since
_get_npx_command() already resolves the correct executable name
(e.g. npx.cmd), making shell dispatch unnecessary.

Fixes modelcontextprotocol#1257

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

1 participant