stata-mcp CVE-2026-47708
CRITICALLifecycle Timeline
2DescriptionCVE.org
Summary
The log_file_name parameter in the stata_do API and CLI is directly interpolated into a Stata command string without sanitization. The security guard (GuardValidator) only scans the do-file content but does not validate this parameter. An attacker can inject arbitrary Stata commands (including shell, python, erase, etc.) by crafting a malicious log_file_name containing quotes, newlines, or Stata command separators.
Details
In src/stata_mcp/stata/stata_do/do.py, both _execute_unix_like and _execute_windows construct a Stata command string using Python f-strings:
commands = f"""
capture log close
{self.generate_log_command(log_file, is_replace)}
...
do "{dofile_path}"
...
"""The generate_log_command method returns:
log_cmd = f'log using "{log_file.as_posix()}", {replace_clause} {log_type} name({log_type}_log)'Where log_file is constructed from user-supplied log_name:
def generate_log_file(self, log_name: str, extension='log'):
return self.log_file_path / f"{log_name}.{extension}"The log_name parameter comes directly from user input (via MCP tool stata_do or CLI stata-mcp tool do) without any validation. Since the path is embedded inside double quotes in a Stata command string, an attacker can break out of the string context and inject arbitrary commands.
Additionally, generate_log_file does not prevent path traversal via log_name, allowing arbitrary file write outside the intended log directory.
Proof of Concept
When calling stata_do via MCP tool with:
{
"dofile_path": "test.do",
"log_file_name": "'; shell echo pwned > /tmp/pwned.txt; '"
}The generated Stata commands become:
log using "<log_dir>/'; shell echo pwned > /tmp/pwned.txt; '.log", replace text name(text_log)Stata interprets this as multiple commands, with shell echo pwned > /tmp/pwned.txt; executed as an arbitrary shell command.
Impact
- Remote Code Execution via
shellcommand injection - Arbitrary file write/overwrite via path traversal in
log_name - Complete bypass of the security guard, as the guard only validates do-file content, not wrapper parameters
Remediation / Fix
- Apply strict allowlist validation to
log_name(only alphanumeric, underscore, dot, hyphen; max 128 chars) - Resolve and verify the constructed log path remains within the intended log directory
- Consider generating safe internal filenames (e.g., UUIDs) instead of accepting user-defined log names for command construction
- Apply similar sanitization to
dofile_pathbefore embedding it into Stata command strings
References
- Issue: #74
- Fix commit: https://github.com/SepineTam/stata-mcp/commit/e6f945941ae0c7cf5e74a428e0b3dc82b396382f
AnalysisAI
Command injection in stata-mcp (MCP-for-Stata) versions prior to 1.17.3 allows attackers to execute arbitrary Stata commands - including the shell directive - by supplying a crafted log_file_name parameter to the stata_do MCP tool or CLI. The flaw bypasses the existing GuardValidator security control, which only inspects do-file content and never examines wrapper parameters, enabling remote code execution and arbitrary file writes via path traversal. Publicly available exploit code exists in the GHSA advisory PoC, though no public exploit identified at time of analysis indicates in-the-wild abuse.
Technical ContextAI
stata-mcp is a Python package (pkg:pip/stata-mcp) implementing a Model Context Protocol (MCP) server that bridges LLM agents to Stata, a statistical computing environment. The vulnerable code in src/stata_mcp/stata/stata_do/do.py builds Stata command strings via Python f-string interpolation, embedding the user-controlled log_name inside double-quoted log using "..." directives. This is a textbook CWE-77 (Improper Neutralization of Special Elements used in a Command) issue: because Stata treats quotes and newlines as command boundaries, an injected payload can close the string and append commands such as shell, python, or erase. The same generate_log_file helper concatenates the user value into a filesystem path with no normalization, also opening a path-traversal write primitive. The vendor's fix commit (e6f9459) introduces a regex allowlist ^[A-Za-z0-9_.-]{1,128}$ and rejects ./.. path components.
RemediationAI
Vendor-released patch: 1.17.3 - upgrade via pip install --upgrade stata-mcp to a version >= 1.17.3, which adds the LOG_FILE_NAME_PATTERN regex allowlist and explicit path-traversal rejection in _validate_log_name (see fix commit https://github.com/SepineTam/mcp-for-stata/commit/e6f945941ae0c7cf5e74a428e0b3dc82b396382f and advisory https://github.com/SepineTam/stata-mcp/security/advisories/GHSA-4p62-hqp5-g644). If immediate upgrade is not possible, restrict who can invoke the stata_do MCP tool or CLI to fully trusted callers, and wrap the call site to reject any log_file_name containing quotes, semicolons, newlines, backslashes, or path separators - note this is a coarse mitigation that may reject some legitimate filenames. As a deployment-level control, run the Stata process under a low-privilege account in a sandboxed working directory so that shell execution and traversal writes are constrained; the trade-off is that legitimate Stata workflows requiring shell access or broad filesystem reach will also break. Also apply the same scrutiny to dofile_path, which the advisory notes is similarly embedded into the command string.
Wazuh SIEM platform versions 4.4.0 through 4.9.0 contain an unsafe deserialization vulnerability in the DistributedAPI t
BentoML version 1.4.2 and earlier contains an unauthenticated remote code execution vulnerability through insecure deser
pgAdmin 4 contains critical remote code execution vulnerabilities in the Query Tool download and Cloud Deployment endpoi
The renderLocalView function in render/views.py in graphite-web in Graphite 0.9.5 through 0.9.10 uses the pickle Python
BentoML is a Python library for building online serving systems optimized for AI apps and model inference. Rated critica
OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph
pyLoad download manager version prior to 0.5.0b3.dev77 exposes the Flask SECRET_KEY through an unauthenticated endpoint.
In Mercurial before 4.1.3, "hg serve --stdio" allows remote authenticated users to launch the Python debugger, and conse
Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/
pyLoad is the free and open-source Download Manager written in pure Python. Rated medium severity (CVSS 5.3), this vulne
Langflow (a visual LLM pipeline builder) contains a critical unauthenticated code execution vulnerability (CVE-2026-3301
Cross-user flow execution in Langflow (< 1.9.1) lets any authenticated API-key holder run another user's flow by passing
Same weakness CWE-77 – Command Injection
View allShare
External POC / Exploit Code
Leaving vuln.today
GHSA-4p62-hqp5-g644