CVE-2026-53753
Crawl4AI insecure eval allows sandbox escape and remote code execution.
- CVSS 10.0
- CWE-94
- Input Validation and Sanitization
- Remote
Crawl4AI is an open-source LLM friendly web crawler & scraper. Prior to 0.8.7, the _safe_eval_expression() function in the computed fields feature uses an AST validator that only blocks attributes starting with underscore. Python generator and frame object attributes (gi_frame, f_back, f_builtins) do NOT start with underscore, enabling a complete sandbox escape to achieve arbitrary code execution. The attack requires no authentication (JWT disabled by default) and is triggered via POST /crawl with a crafted extraction schema. This vulnerability is fixed in 0.8.7.
- CWE
- CWE-94
- CVSS base score
- 10.0
- Published
- 2026-06-23
- OWASP
- A03 Injection
- Orthogonal defect classification
- Checking
- Code defect classification
- Incorrect Check
- Category
- Input Validation and Sanitization
- Subcategory
- Insecure Parsing or Deserialization
- Accessibility scope
- Remote
- Impact
- Arbitrary Code Execution
- Affected component
- Crawl4AI
- Fixed by upgrading
- Yes
Solution
Upgrade to Crawl4AI version 0.8.7 or later.
Vulnerable code sample
import ast
class FlawedASTValidator(ast.NodeVisitor):
def visit_Attribute(self, node):
# The vulnerability: only attributes starting with '_' are blocked.
# Attributes like 'gi_frame', 'f_back', and 'f_builtins' are allowed.
if node.attr.startswith('_'):
raise ValueError("Access to private attributes is not allowed.")
self.generic_visit(node)
def _safe_eval_expression(expression: str, context: dict = None) -> any:
"""
This function simulates the vulnerable behavior from Crawl4AI prior to 0.8.7.
It uses a flawed AST check before evaluating a user-provided expression,
making it vulnerable to a sandbox escape and remote code execution.
"""
if context is None:
context = {}
tree = ast.parse(expression, mode='eval')
validator = FlawedASTValidator()
validator.visit(tree)
code_obj = compile(tree, filename='<string>', mode='eval')
# The globals dictionary is restricted, but the payload can bypass this
# by accessing frame objects that are not blocked by the validator.
return eval(code_obj, {"__builtins__": {}}, context)Patched code sample
import ast
class SecurityError(Exception):
"""Custom exception for security violations in safe_eval."""
pass
# Allowlist of safe built-in functions
_ALLOWED_BUILTINS = {
'str', 'int', 'float', 'len', 'list', 'dict', 'set', 'tuple',
'max', 'min', 'sum', 'abs', 'round', 'any', 'all', 'sorted',
'isinstance', 'range'
}
# Allowlist of safe attributes, which is the core of the fix.
# It prevents access to dangerous attributes like 'gi_frame', 'f_back', etc.
_ALLOWED_ATTRIBUTES = {
# Common and safe string attributes
'strip', 'split', 'replace', 'lower', 'upper', 'title', 'capitalize',
# Common and safe list/dict attributes
'append', 'extend', 'insert', 'remove', 'pop', 'clear', 'index', 'count', 'sort', 'reverse', 'copy',
'keys', 'values', 'items', 'get',
}
class _SafeExpressionValidator(ast.NodeVisitor):
"""
AST visitor to validate expressions for safe evaluation.
This fixed version uses an allowlist for attribute access.
"""
def visit_Call(self, node: ast.Call) -> None:
if isinstance(node.func, ast.Name) and node.func.id not in _ALLOWED_BUILTINS:
raise SecurityError(f"Calling the function '{node.func.id}' is not allowed.")
self.generic_visit(node)
def visit_Attribute(self, node: ast.Attribute) -> None:
# Still blocks attributes starting with underscore as a first-level defense.
if node.attr.startswith('_'):
raise SecurityError(f"Access to private attribute '{node.attr}' is not allowed.")
# ** THE FIX **
# Checks the attribute against a safe allowlist, preventing access to
# dangerous attributes like 'gi_frame', 'f_globals', 'f_builtins', etc.
if node.attr not in _ALLOWED_ATTRIBUTES:
raise SecurityError(f"Access to attribute '{node.attr}' is not allowed for security reasons.")
self.generic_visit(node)
# Example of how this validator would be used in the safe evaluation function.
# The original vulnerable function did not have the `if node.attr not in _ALLOWED_ATTRIBUTES:` check.
def _safe_eval_expression(expression: str, context: dict):
"""
Safely evaluates a Python expression string.
"""
try:
tree = ast.parse(expression, mode='eval')
validator = _SafeExpressionValidator()
validator.visit(tree)
# The 'builtins' dictionary is carefully controlled.
safe_builtins = {b: __builtins__[b] for b in _ALLOWED_BUILTINS if b in __builtins__}
# Evaluation is done with a restricted global and local context.
return eval(compile(tree, filename='<string>', mode='eval'), {"__builtins__": safe_builtins}, context)
except (SecurityError, SyntaxError, NameError, TypeError, Exception) as e:
raise SecurityError(f"Failed to safely evaluate expression: {e}") from ePayload
{
"url": "http://example.com",
"extraction_schema": {
"computed_fields": [
{
"field": "rce",
"expression": "(c for c in []).gi_frame.f_globals['__builtins__']['__import__']('os').system('id')"
}
]
}
}
Cite this entry
@misc{vaitp:cve202653753,
title = {{Crawl4AI insecure eval allows sandbox escape and remote code execution.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-53753},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-53753/}}
}
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 ::
