CVE-2025-68271

Houston, We Have an `eval()`: Pre-Auth RCE in OpenC3 COSMOS

Alon Barad
Alon Barad
Software Engineer

Jan 14, 2026·6 min read

Executive Summary (TL;DR)

OpenC3 COSMOS, software used for satellite command and control, was caught using Ruby's `eval()` to parse strings that looked like arrays. Because this parsing happens before authentication checks in the JSON-RPC API, any unauthenticated attacker can send a crafted packet to execute code as the server user. It's literally a case of 'If it looks like an array, execute it.'

A Critical (10.0) pre-authentication Remote Code Execution vulnerability in OpenC3 COSMOS allows attackers to execute arbitrary commands on mission control servers via the JSON-RPC interface. The flaw stems from the insecure use of `eval()` when parsing array-like strings.

The Hook: Rocket Science Meets Script Kiddie

Space is hard. Orbital mechanics, thermal vacuum testing, and link budgets are complex problems that require brilliant minds. OpenC3 COSMOS is the software designed to handle this complexity, providing command and control for satellites, test benches, and drones. It is the brain of the operation. Ideally, you want that brain to be secure.

However, in late 2025, it was discovered that this mission-critical software had a vulnerability so simple, so ancient, and so devastating that it feels like a prank from the 90s. We aren't talking about a complex heap grooming exploit or a subtle race condition in the kernel. We are talking about the cardinal sin of dynamic languages: passing untrusted user input directly into eval().

What makes this particularly spicy is the context. This isn't just a blog engine; it's software capable of moving hardware. An attacker finding this endpoint doesn't just get a shell; in a worst-case scenario, they get to drive the test bench. It’s a perfect example of how high-level logic flaws can undermine the most 'secure' operational environments.

The Flaw: If It Quacks Like an Array...

The vulnerability lies deep within the utility functions of COSMOS, specifically in how it converts string parameters into Ruby objects. The developers needed a way to handle incoming data that might be a number, a boolean, or an array. Their solution for arrays was... optimistic.

The logic was effectively this: "Does the string start with a square bracket [ and end with a square bracket ]? If yes, it must be an array! Let's just run it as code to turn it into a real array." This is defined in openc3/lib/openc3/core_ext/string.rb.

The regex used was ARRAY_CHECK_REGEX = /\A\s*\[.*\]\s*\z/. This regex checks if the string looks vaguely like a list. If it matches, the code passes the entire string to Ruby's eval(). There is no sanitization, no tokenization, just a blind trust that the user only put commas and numbers inside those brackets. Spoiler: The user can put system('rm -rf /') inside those brackets.

The Code: The Smoking Gun

Let's look at the vulnerable code. This is a classic example of "convenience over security." The method convert_to_value is mixed into the String class.

Vulnerable Code:

# openc3/lib/openc3/core_ext/string.rb
elsif self.is_array?
  # It matches /\A\s*\[.*\]\s*\z/ so it must be safe, right?
  return_value = eval(self)

If I send the string "[1, 2, 3]", eval runs it and returns a Ruby array [1, 2, 3]. But if I send "[system('id')]", eval runs the system command. The return value is the result of the command, but the side effect (executing code) happens immediately.

The Fix: The patch replaces the dangerous eval() with YAML.safe_load. The YAML parser in Ruby (Psych) is designed to parse data structures without executing code (unless you explicitly enable unsafe marshaling).

# PATCHED CODE
elsif self.is_array? or self.is_object?
  # Array or Object
  return_value = YAML.safe_load(self)

They also fixed a similar issue in the Python support library, swapping eval() for ast.literal_eval(), which is the correct way to parse literals in Python safely.

The Exploit: Bypassing the Bouncer

You might be thinking, "Surely this API is behind a login screen?" Yes, it is. But here is the kicker: Argument parsing happens before Authorization.

When a request hits the JSON-RPC cmd endpoint, the server needs to figure out what parameters are being passed to the method before it decides if you are allowed to call that method. It iterates through the parameters, sees a string that looks like an array, and helpfully tries to convert it for you. This conversion triggers the eval().

The Attack Chain:

  1. Target: POST /api/cmd (or similar JSON-RPC gateway).
  2. Payload:
    {
      "jsonrpc": "2.0",
      "method": "any_method",
      "params": ["[#{\"touch /tmp/pwned\"}]"],
      "id": 1
    }
  3. Execution: The Ruby backend sees the brackets. It evaluates the string interpolation #{...} inside the string. The command executes.
  4. Response: The server eventually checks permissions, realizes you aren't logged in, and returns 401 Unauthorized. But it's too late. The code has already run.

This is a classic "Time-of-Check to Time-of-Use" style logic flaw, but applied to the order of operations in an API controller.

The Impact: From Zero to Mission Control

The CVSS score is 10.0 for a reason. This requires no authentication, no user interaction, and works over the network. The compromised process is the COSMOS web backend, which typically runs inside a container or on a server with direct network access to the hardware it controls.

Scenario A: Espionage. An attacker silently exfiltrates telemetry data, configuration files, and proprietary command scripts. In the aerospace industry, this IP is invaluable.

Scenario B: Sabotage. Because COSMOS sends commands to embedded systems, an attacker could potentially send commands to hardware. If this is a thermal vacuum chamber or a satellite on a test bench, valid commands sent at the wrong time (e.g., "Turn on heaters") could physically destroy million-dollar hardware.

Scenario C: Lateral Movement. The COSMOS server is often a bridge between the corporate IT network and the isolated OT (Operational Technology) network. compromising this box gives the attacker a pivot point into the most sensitive part of the infrastructure.

The Mitigation: Stop the Bleeding

If you are running OpenC3 COSMOS versions 5.0.0 through 6.10.1, you are vulnerable. The patch is available in version 6.10.2.

Immediate Steps:

  1. Update: Pull the latest docker images or update your source install immediately.
  2. Firewall: Ensure your COSMOS instance is NOT exposed to the public internet. If it is, assume it is compromised. Restrict access to port 2900 (and others) to a VPN or specific management IPs.
  3. WAF: If you cannot update immediately, a WAF rule blocking POST bodies containing [" followed by common Ruby gadget chains (like Kernel, system, backticks, IO.popen) might buy you some time, but regex-based WAFs are notoriously bypassable against code injection.

For developers reading this: Never, ever use eval() to parse data. Use JSON.parse(), YAML.safe_load(), or ast.literal_eval(). If you find yourself writing a regex to check if a string is code... stop. You are already losing.

Fix Analysis (1)

Technical Appendix

CVSS Score
10.0/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H

Affected Systems

OpenC3 COSMOS 5.0.0 - 6.10.1Satellite Ground Systems using COSMOSHardware-in-the-loop Test Benches

Affected Versions Detail

Product
Affected Versions
Fixed Version
OpenC3 COSMOS
OpenC3
>= 5.0.0, <= 6.10.16.10.2
AttributeDetail
CWECWE-95 (Eval Injection)
CVSS v3.110.0 (Critical)
Attack VectorNetwork (Pre-Auth)
Affected ComponentString#convert_to_value
LanguageRuby / Python
Exploit ReliabilityHigh (Deterministic)
CWE-95
Improper Neutralization of Directives in Dynamically Evaluated Code ('Eval Injection')

The software receives input from an upstream component, but it does not neutralize or incorrectly neutralizes code syntax before using the input in a dynamic evaluation call (e.g. 'eval').

Vulnerability Timeline

Patch committed to GitHub
2025-12-14
GHSA Advisory Published
2026-01-13

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.