CVE-2026-55546 Microsoft Sentinel · KQL

Detect qwed-mcp Unsafe SymPy parse_expr() Remote Code Execution (CVE-2026-55546) in Microsoft Sentinel

Detects exploitation of CVE-2026-55546, a critical (CVSS 9.8) code-injection vulnerability (CWE-94) in the qwed-mcp Python package (< 0.2.1). qwed-mcp is a Model Context Protocol (MCP) server exposing math tools that pass user-supplied expression strings directly to SymPy's parse_expr() without restricting the evaluation namespace or transformations. Because parse_expr() will evaluate Python-callable constructs, an attacker can craft a math expression that invokes arbitrary Python (e.g. via __import__, object attribute traversal, or eval-reachable builtins), achieving remote code execution in the process hosting the MCP server. This detection surfaces the MCP server process spawning unexpected child processes (shell/interpreter/network tools), suspicious inbound tool-call payloads containing Python injection primitives, and installation of vulnerable package versions.

MITRE ATT&CK

Tactic
Initial Access Execution

KQL Detection Query

Microsoft Sentinel (KQL)
kusto
let mcpParents = dynamic(["python","python3","python3.11","python3.12","uvicorn","uv","gunicorn"]);
let suspChildren = dynamic(["sh","bash","zsh","dash","cmd.exe","powershell.exe","pwsh","curl","wget","nc","ncat","whoami","id","python","python3"]);
DeviceProcessEvents
| where InitiatingProcessFileName has_any (mcpParents)
| where InitiatingProcessCommandLine has_any ("qwed-mcp","qwed_mcp","qwed")
| where FileName in~ (suspChildren)
| where not(ProcessCommandLine has_any ("pip install","pytest","site-packages"))
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName, InitiatingProcessCommandLine, FileName, ProcessCommandLine, ProcessId, InitiatingProcessId
| order by Timestamp desc
critical severity medium confidence

Flags the qwed-mcp server (Python/uvicorn parent whose command line references qwed-mcp) spawning shells, interpreters, or network tooling — the expected post-exploitation signal of parse_expr() RCE.

Data Sources

Microsoft Defender for EndpointDeviceProcessEvents

Required Tables

DeviceProcessEvents

False Positives & Tuning

  • Legitimate qwed-mcp maintenance scripts that shell out during package upgrades or health checks
  • Developer running the server interactively and spawning a subshell for debugging
  • Container entrypoints where the Python parent legitimately launches sh to wrap the server

Other platforms for CVE-2026-55546


Testing Methodology

Validate this detection against 3 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.

  1. Test 1Simulate parse_expr injection spawning a shell

    Expected signal: Process creation event: python3 parent spawning sh -> id, with command line referencing __import__/os.system

  2. Test 2Malicious MCP tool-call payload with injection primitives

    Expected signal: MCP application log records a tool-call whose expression argument contains __class__/__subclasses__

  3. Test 3Detect vulnerable qwed-mcp version installed

    Expected signal: Process execution of pip show; inventory output showing qwed-mcp version


Response Playbook

Triage

  1. Confirm the alerting host runs qwed-mcp and check the installed version: `pip show qwed-mcp` — versions < 0.2.1 are vulnerable.
  2. Retrieve the parent qwed-mcp process command line and the child process spawned; determine whether the child is a shell, interpreter, or network tool with no legitimate business justification.
  3. Pull the MCP server's request/tool-call logs around the alert time and inspect the math-expression argument for Python injection primitives (__import__, __class__, __subclasses__, os., subprocess, eval, exec, lambda).
  4. Identify the source of the malicious tool call (client IP, MCP session ID, upstream LLM agent) to scope whether exploitation was internal or externally reachable.

Containment

  1. Isolate the affected host from the network (EDR containment) to prevent attacker follow-on actions and C2.
  2. Stop the qwed-mcp service and block inbound access to its listening port until it is upgraded to >= 0.2.1.
  3. Rotate any credentials, API keys, or tokens accessible to the qwed-mcp process, as they must be considered compromised.

Evidence Collection

  1. Capture the full process tree (parent qwed-mcp and all descendants), including command lines, PIDs, and timestamps.
  2. Preserve qwed-mcp application logs and MCP tool-call payloads containing the malicious expression.
  3. Collect network connection logs (netstat/EDR) for outbound connections initiated by the qwed-mcp process or its children.
  4. Snapshot the host memory and disk if RCE is confirmed for forensic analysis of dropped payloads.

Escalation Criteria

  • !Escalate to incident response if a child process established an outbound network connection or dropped/executed a secondary payload.
  • !Escalate if the qwed-mcp instance was internet-facing or reachable by untrusted MCP clients, indicating potential external compromise.
  • !Escalate if credential theft, lateral movement, or persistence artifacts are found following the initial code execution.

Investigation Guide

Related Techniques

Forensic Artifacts

  • >qwed-mcp application/tool-call logs containing the malicious math expression
  • >Process creation records (Sysmon EID 1 / auditd execve) showing the qwed-mcp parent spawning unexpected children
  • >Outbound network connection logs from the qwed-mcp process
  • >Any files written to temp/working directories by spawned child processes

Tuning Guidance

Baseline the legitimate child processes of your qwed-mcp deployment (e.g., health-check scripts, container entrypoint wrappers) and add them to an allowlist. If qwed-mcp runs inside a container with a known static command line, tighten the parent-command-line match to that exact invocation. Exclude known package-management and test activity (pip, pytest, uv) by user and path. After upgrading all instances to >= 0.2.1, downgrade severity to informational and retain the rule for regression detection.


Hunting Queries

Hunt across the estate for any qwed-mcp process spawning shells or network tooling, grouping by host and child process to surface exploitation clusters.

Hunting — KQL
kql
DeviceProcessEvents | where InitiatingProcessCommandLine has_any ("qwed-mcp","qwed_mcp") | where FileName in~ ("sh","bash","curl","wget","nc","python3","whoami","id") | summarize count() by DeviceName, FileName, ProcessCommandLine, bin(Timestamp, 1h)
Hunting — SPL
spl
index=* ("qwed-mcp" OR "qwed_mcp") (process_name IN ("sh","bash","curl","wget","nc","whoami","id")) | stats count by host, process_name, process | sort - count

Atomic Red Team Tests

Test 1 Simulate parse_expr injection spawning a shell
linux

Reproduces the RCE effect by having a Python process (standing in for qwed-mcp) evaluate an untrusted SymPy-style expression that reaches os.system, spawning a shell.

Command

bash
python3 -c "from sympy import parse_expr; import sympy; parse_expr('__import__(\"os\").system(\"id > /tmp/qwed_poc.txt\")', evaluate=True)" 2>/dev/null; cat /tmp/qwed_poc.txt

Cleanup

bash
rm -f /tmp/qwed_poc.txt

Expected Telemetry

Process creation event: python3 parent spawning sh -> id, with command line referencing __import__/os.system

Expected Detection

KQL/SPL/EQL rules fire on the python parent spawning sh/id child process

Test 2 Malicious MCP tool-call payload with injection primitives
linux

Sends a crafted math expression containing Python injection primitives to a locally running qwed-mcp instance (lab) to generate a suspicious tool-call log entry.

Command

bash
curl -s -X POST http://127.0.0.1:8000/mcp -H 'Content-Type: application/json' -d '{"tool":"evaluate","expression":"().__class__.__base__.__subclasses__()"}'

Cleanup

bash
echo 'no cleanup required; review and purge test tool-call logs if desired'

Expected Telemetry

MCP application log records a tool-call whose expression argument contains __class__/__subclasses__

Expected Detection

Log-based hunting query flags injection primitives in the expression payload

Test 3 Detect vulnerable qwed-mcp version installed
linux

Enumerates the installed qwed-mcp package version to identify hosts running affected releases (< 0.2.1).

Command

bash
pip show qwed-mcp 2>/dev/null | grep -i version || echo 'qwed-mcp not installed'

Cleanup

bash
echo 'no cleanup required'

Expected Telemetry

Process execution of pip show; inventory output showing qwed-mcp version

Expected Detection

Vulnerability management correlation flags qwed-mcp version below 0.2.1

Related Detections