Multiple MCP tool handlers in main.py construct shell commands by directly interpolating user-controlled parameters into f-strings, which are then executed via asyncio.create_subprocess_shell() in esp_utils.py . An attacker (or a prompt-injected AI assistant) can inject arbitrary shell commands through parameters like target , port , project_name , test_path , pytest_args , and idf_path .
Severity: 9.8 Critical (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) CWE: CWE-78 (Improper Neutralization of Special Elements used in an OS Command)
Vulnerability Details
esp_utils.py defines run_command_async() which passes a string directly to asyncio.create_subprocess_shell() :
All 6 tool handlers in main.py construct commands using f-string interpolation with user-controlled MCP parameters, then pass them to this function.
Affected Tools and Injectable Parameters
6 tools, 10 injectable parameters.
Notably, sdkconfig_defaults in build_esp_project IS properly sanitized with shlex.quote() , demonstrating that the developer was aware of the risk for that one parameter but missed all others.
1. Command injection via target parameter
The setup_project_esp_target tool constructs:
An attacker provides:
Resulting shell command:
The single quote in target closes the bash -c argument, and && id > /tmp/pwned executes as a separate command.
2. Command injection via port parameter
The flash_esp_project tool constructs:
An attacker provides:
3. Command injection via pytest_args parameter
The run_pytest tool constructs:
An attacker provides:
4. Command injection via idf_path parameter
idf_path flows through get_export_script() → os.path.join(idf_path, 'export.sh') → f-string interpolation:
An attacker provides:
In the MCP threat model, the AI assistant selects tool parameters based on user instructions and context. A malicious document, webpage, or prompt injection can manipulate the AI into calling these tools with crafted parameter values, achieving remote code execution on the machine running the MCP server.
Remote Code Execution : Arbitrary commands execute with the privileges of the MCP server process
Data Exfiltration : Read sensitive files, environment variables, credentials
System Compromise : Install backdoors, pivot to other systems
Supply Chain Risk : Modify ESP-IDF projects or toolchain binaries during build
Use shlex.quote() on ALL user-controlled parameters before interpolation (as already done for sdkconfig_defaults ), or better yet, switch from create_subprocess_shell to asyncio.create_subprocess_exec with argument lists:
Apply to all 10 injectable parameters across all 6 tools.
Issue #48 reports CWE-22 (Path Traversal) for idf_path in run_esp_idf_install — an existence oracle via error messages. This report covers the far more severe CWE-78 (Command Injection) across all tools, where the same parameters enable arbitrary code execution through shell metacharacter injection. These are distinct vulnerability classes with different impacts.
The full story
This article is one source in a clustered incident — the cluster page carries the summary, timeline and every other outlet covering it.
