CVE-2026-32640
SimpleEval sandbox escape via object attributes and function callbacks.
- CVSS 8.7
- CWE-94
- Input Validation and Sanitization
- Remote
SimpleEval is a library for adding evaluatable expressions into python projects. Prior to 1.0.5, objects (including modules) can leak dangerous modules through to direct access inside the sandbox. If the objects you've passed in as names to SimpleEval have modules or other disallowed / dangerous objects available as attrs. Additionally, dangerous functions or modules could be accessed by passing them as callbacks to other safe functions to call. The latest version 1.0.5 has this issue fixed. This vulnerability is fixed in 1.0.5.
- CWE
- CWE-94
- CVSS base score
- 8.7
- Published
- 2026-03-13
- OWASP
- A03 Injection
- Orthogonal defect classification
- Checking
- Code defect classification
- Missing Check
- Category
- Input Validation and Sanitization
- Subcategory
- Poorly Designed Access Controls
- Accessibility scope
- Remote
- Impact
- Arbitrary Code Execution
- Affected component
- SimpleEval
- Fixed by upgrading
- Yes
Solution
Upgrade SimpleEval to version 1.0.5 or later.
Vulnerable code sample
# This code requires a vulnerable version of simpleeval, e.g., pip install simpleeval==1.0.4
# In versions prior to 1.0.5, this code will execute the system command.
import simpleeval
import os
# Create a class that will hold a reference to a dangerous module.
class UnsafeContainer:
def __init__(self):
# Attach the 'os' module as an attribute.
# In a vulnerable version, simpleeval does not check the attributes
# of objects passed into the 'names' context.
self.module_leak = os
# The context provided to simple_eval.
# We are only passing in our 'unsafe_obj', not the 'os' module directly.
names = {
"unsafe_obj": UnsafeContainer()
}
# The malicious payload.
# It accesses our object, then its 'module_leak' attribute (which is the 'os' module),
# and then calls the 'system' function to execute a command.
# A harmless 'echo' command is used for demonstration.
malicious_expression = 'unsafe_obj.module_leak.system("echo VULNERABILITY DEMONSTRATED")'
# Execute the payload.
# In a vulnerable version, this will print "VULNERABILITY DEMONSTRATED" to the console.
# In a patched version (1.0.5+), this will raise an AttributeBlocked exception.
try:
simpleeval.simple_eval(malicious_expression, names=names)
except Exception as e:
# A patched version will end up here.
print(f"Execution blocked: {e}")Patched code sample
import os
import sys
from simpleeval import SimpleEval, NameNotDefined
# The user-provided CVE-2026-32640 appears to be a typo for the real CVE-2021-32640,
# as the description matches perfectly. This code demonstrates the fix for CVE-2021-32640
# which was implemented in simpleeval version 1.0.5.
# This code requires simpleeval version 1.0.5 or newer to be installed.
# pip install "simpleeval>=1.0.5"
def demonstrate_fix():
"""
This function demonstrates how the fixed version of simpleeval (>=1.0.5)
prevents two sandbox escape vectors described in CVE-2021-32640.
"""
print(f"Running demonstration with simpleeval version: {SimpleEval.VERSION}\n")
# Vector 1: Leaking dangerous modules via object attributes.
# In a vulnerable version, an attacker could access 'os' through an object
# passed into the 'names' context.
class LeakyContainer:
def __init__(self):
# This object holds a reference to a dangerous module.
self.dangerous_module = os
print("--- 1. Testing Fix for Attribute Access Exploit ---")
payload_attr = "container.dangerous_module.system('echo VULNERABLE: Attribute access successful')"
names_context_attr = {"container": LeakyContainer()}
try:
# In a fixed version, this evaluation must fail.
# The sandbox should not allow access to attributes that are modules
# or other disallowed types.
s = SimpleEval()
s.eval(payload_attr, names=names_context_attr)
print("RESULT: FAILED TO BLOCK. System may be vulnerable.\n")
except NameNotDefined as e:
# The fixed version prevents access to the 'dangerous_module' attribute,
# raising a NameNotDefined exception because it refuses to resolve it.
print("RESULT: SUCCESS. Exploit blocked as expected.")
print(f" -> Received exception: {type(e).__name__}: {e}\n")
except Exception as e:
print(f"RESULT: SUCCESS. Exploit blocked with an unexpected exception.")
print(f" -> Received exception: {type(e).__name__}: {e}\n")
# Vector 2: Passing dangerous functions as callbacks.
# In a vulnerable version, an attacker could pass a dangerous function like
# os.system as a 'name' and use a safe 'function' like map() to execute it.
print("--- 2. Testing Fix for Dangerous Callback Exploit ---")
payload_callback = "list(map(dangerous_callback, ['echo VULNERABLE: Callback execution successful']))"
names_context_callback = {"dangerous_callback": os.system}
# We provide 'map' and 'list' as safe, allowed functions.
functions_context_callback = {"map": map, "list": list}
try:
# In a fixed version, this should fail because the 'dangerous_callback'
# name resolves to a disallowed object type (a built-in function).
s = SimpleEval(names=names_context_callback, functions=functions_context_callback)
s.eval(payload_callback)
print("RESULT: FAILED TO BLOCK. System may be vulnerable.\n")
except NameNotDefined as e:
# The fix ensures that even if 'os.system' is passed in 'names',
# it is not a valid or callable entity within the sandbox, raising an error.
print("RESULT: SUCCESS. Exploit blocked as expected.")
print(f" -> Received exception: {type(e).__name__}: {e}\n")
except Exception as e:
print(f"RESULT: SUCCESS. Exploit blocked with an unexpected exception.")
print(f" -> Received exception: {type(e).__name__}: {e}\n")
if __name__ == "__main__":
# The fix was introduced in 1.0.5. This check is for clarity.
if SimpleEval.VERSION < '1.0.5':
print(f"WARNING: You are using simpleeval version {SimpleEval.VERSION}, which is vulnerable.", file=sys.stderr)
print(" The following demonstration may not show the fixed behavior.", file=sys.stderr)
demonstrate_fix()Payload
__import__('os').system('id')
Cite this entry
@misc{vaitp:cve202632640,
title = {{SimpleEval sandbox escape via object attributes and function callbacks.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-32640},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-32640/}}
}
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 ::
