CVE-2026-2275
CrewAI CodeInterpreter's unsafe fallback to SandboxPython enables RCE.
- CVSS 9.6
- CWE-749
- Design Defects
- Remote
The CrewAI CodeInterpreter tool falls back to SandboxPython when it cannot reach Docker, which can enable RCE through arbitrary C function calling.
- CWE
- CWE-749
- CVSS base score
- 9.6
- Published
- 2026-03-30
- OWASP
- A06 Vulnerable and Outdated Components
- Orthogonal defect classification
- Algorithm
- Code defect classification
- Incorrect Algorithm
- Category
- Design Defects
- Subcategory
- Inadequate Error Handling
- Accessibility scope
- Remote
- Impact
- Arbitrary Code Execution
- Affected component
- CrewAI
- Fixed by upgrading
- Yes
Solution
Upgrade `crewai` to version 0.35.9 or later.
Vulnerable code sample
import subprocess
import sys
import os
import uuid
# The code below is a conceptual representation of the vulnerable logic
# present in the CrewAI CodeInterpreterTool before it was patched.
# The core of the vulnerability was the fallback from a secure Docker
# environment to an insecure local subprocess execution when Docker was
# not available.
class VulnerableCodeInterpreter:
def _execute_code(self, code: str) -> str:
"""
A method that attempts to run code in Docker and falls back
to a local subprocess, demonstrating the vulnerability.
"""
# In the original code, a temporary file was often used.
file_path = f"temp_code_{uuid.uuid4()}.py"
with open(file_path, "w") as f:
f.write(code)
try:
# 1. Attempt to use a secure, sandboxed environment (Docker).
# In this demonstration, we simulate that the Docker daemon is
# not available by immediately raising an exception.
# In the real code, this would involve using the `docker` library.
raise ConnectionError("Simulated failure: Docker daemon is not running.")
# The actual code would have looked something like this:
#
# import docker
# client = docker.from_env()
# container = client.containers.run(
# 'python:3.11-slim',
# f'python {file_path}',
# remove=True,
# volumes={os.getcwd(): {'bind': '/app', 'mode': 'rw'}},
# working_dir='/app'
# )
# output = container.decode('utf-8')
except (ConnectionError, Exception):
# 2. VULNERABLE FALLBACK: If the Docker attempt fails, the code
# falls back to executing the script directly on the host
# machine using a subprocess. This is not sandboxed and
# allows for Remote Code Execution (RCE).
result = subprocess.run(
[sys.executable, file_path],
capture_output=True,
text=True
)
output = result.stdout or result.stderr
finally:
# 3. Clean up the temporary file.
if os.path.exists(file_path):
os.remove(file_path)
return outputPatched code sample
import docker
import os
import io
# This code demonstrates a hypothetical fix for the described vulnerability.
# The vulnerability was a dangerous fallback to a less secure execution
# environment when a primary, secure one (Docker) was unavailable.
#
# The fix is to REMOVE the insecure fallback entirely. If the secure
# environment cannot be initialized, the tool should fail explicitly
# and refuse to execute any code, rather than silently switching to
# a vulnerable mode.
class CodeInterpreterTool:
"""
A tool for executing Python code in a secure, isolated Docker environment.
This version has been fixed to prevent a fallback to an insecure
execution method. It will now raise an exception during initialization if
a connection to Docker cannot be established, ensuring that code is never
run outside of the intended sandboxed container.
"""
_docker_client = None
_image_name: str = "python:3.11-slim"
def __init__(self):
try:
self._docker_client = docker.from_env()
# The ping() method confirms that the Docker daemon is running and accessible.
if not self._docker_client.ping():
raise docker.errors.DockerException
# Ensure the required Docker image is available locally
try:
self._docker_client.images.get(self._image_name)
except docker.errors.ImageNotFound:
print(f"Pulling required Docker image: {self._image_name}...")
self._docker_client.images.pull(self._image_name)
except docker.errors.DockerException as e:
# FIX: Instead of falling back to a different sandbox, we raise an error.
# This ensures that the tool cannot be used in an insecure state.
raise EnvironmentError(
"Docker is not running or is not accessible. "
"The CodeInterpreterTool requires a running Docker daemon "
"to execute code securely. Insecure fallbacks have been removed."
) from e
def execute(self, code: str) -> str:
"""
Executes the given Python code inside a Docker container and returns the output.
Args:
code: A string containing the Python code to be executed.
Returns:
A string containing the stdout and stderr from the code execution.
"""
if self._docker_client is None:
# This check is redundant if __init__ is always called, but serves as a safeguard.
raise RuntimeError("Docker client not initialized. Cannot execute code.")
try:
container = self._docker_client.containers.run(
image=self._image_name,
command=["python", "-c", code],
detach=False,
remove=True, # Automatically remove the container when it exits
stderr=True,
stdout=True
)
# The output from the container is bytes, so we decode it to a string.
return container.decode('utf-8')
except docker.errors.ContainerError as e:
# This error occurs if the code inside the container returns a non-zero exit code.
return f"Error executing code in container: {e.stderr.decode('utf-8')}"
except Exception as e:
return f"An unexpected error occurred with Docker: {str(e)}"
# --- Demonstration of the fix ---
if __name__ == "__main__":
print("Attempting to initialize the fixed CodeInterpreterTool...")
# This block will only succeed if you have Docker installed and running.
# If Docker is not available, it will raise the EnvironmentError from __init__.
try:
code_interpreter = CodeInterpreterTool()
print("✅ Tool initialized successfully (Docker is running).")
# Example 1: Benign code execution
print("\n--- Running benign code ---")
benign_code = "print('Hello from the secure container!')"
output = code_interpreter.execute(benign_code)
print(f"Output:\n{output}")
# Example 2: Code that would have been dangerous in the vulnerable version.
# This code attempts to use ctypes, which could lead to RCE on the host
# in a weak sandbox. Here, it will be safely contained within Docker.
# It will likely fail because system commands like 'touch' may not
# be available or have permissions, but it won't affect the host machine.
print("\n--- Running potentially malicious code (safely) ---")
malicious_code_attempt = """
import ctypes
import os
try:
# This command will only run inside the isolated container.
# It cannot affect the host system.
os.system('echo "This is running inside the container" > /tmp/test.txt && cat /tmp/test.txt')
except Exception as e:
print(f"Could not execute system command: {e}")
"""
output = code_interpreter.execute(malicious_code_attempt)
print(f"Output:\n{output}")
except EnvironmentError as e:
print("\n--- Test Result: FAILED TO INITIALIZE ---")
print(f"❌ ERROR: {e}")
print("\nThis is the expected and correct behavior when Docker is not available.")
print("The tool has safely prevented execution instead of using an insecure fallback.")Payload
import ctypes
libc = ctypes.CDLL(None)
command = b"id"
libc.system(command)
Cite this entry
@misc{vaitp:cve20262275,
title = {{CrewAI CodeInterpreter's unsafe fallback to SandboxPython enables RCE.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-2275},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-2275/}}
}
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 ::
