Skip to content Skip to footer

OpenC3 Cosmos 6.0.0: A Security Assessment of an Open-Source Mission Framework

Written by: Andrzej Olchawa, Ricardo Fradique, Milenko Starcik

OpenC3 Cosmos is an open-source command and control software suite designed to support space mission operations. Despite its modularity and widespread adoption across the industry, a recent security assessment of version 6.0.0 uncovered several critical vulnerabilities that could compromise mission-critical systems’ confidentiality, integrity, and availability.

Key Findings

The security assessment uncovered a range of vulnerabilities, including:

  • Cross-Site Scripting (XSS) in multiple tools within the web interface 
  • Remote Code Execution (RCE) via malicious plugin installation and improper script execution
  • Arbitrary File Access and Manipulation through path traversal in multiple API endpoints
  • Credential Leakage through modifiable environment variables in containers
  • Insecure Authentication Mechanisms, including clear-text password usage and undocumented service accounts

 

Based on these, seven CVEs have been assigned:

These findings underscore the need for stricter input validation, access control, and container hardening in mission software deployments.

For more information, watch the video below:

1. XSS in the Documentation Tool (CVE-2025-28380)

The Cosmos Documentation tool allows for injecting JavaScript code from a user-controlled URL parameter. This can be combined with the Script Runner tool to automatically exfiltrate the session token stored on the browser’s Local Storage or obtain Remote Code Execution in the Script Runner engine’s docker container.

Figure 1 – A reverse shell is obtained through JavaScript code injected into the URL.

Steps To Reproduce

In its default configuration, Cosmos includes a Documentation tool that displays the application’s documentation from static files (Figure 3). These are displayed inside an iframe where the Title and Source are obtained from URL parameters (Figure 2).

Figure 2 – Documentation tool Vue template filling the URL and title from user input.

Figure 3 – Cosmos Documentation tool display.

A Content Security Policy (CSP) is in place (Figure 4). However, it allows for unsafe inline and eval execution. While it’s impossible to execute external code, this makes it possible to execute any code on the webpage.

Figure 4 – Cosmos CSP entry.

Since the iframe source is user-controlled, JavaScript can be directly injected into this parameter (Figure 5).

Figure 5 – XSS on the Documentation tool page.

In addition, sessions are managed using a Token saved in the browser’s Local Storage, which can be accessed by all JavaScript code executing on the page (Figure 6):

Figure 6 – Authentication token saved in Local Storage.

Furthermore, the Script Runner tool can execute commands as the host system (Figure 7).

Figure 7 – Script Runner is calling the local command.

Combining these factors, it is possible to create a JavaScript payload that will read the Token from Local Storage and use it in a sequence of POST requests to create and execute a new script with the intended command running on the script engine’s host (Figure 8).

Figure 8 – Clear text payload used to obtain a reverse shell from the Script Runner host.

Figure 9 – Final URL with a base 64 encoded payload.

A PoC was created to help generate malicious links for arbitrary command payloads (Figure 10).

Figure 10 – PoC generates a payload to exfiltrate the authentication token.

While the impact is that any application functionality and system command can be triggered from this payload, a logged-in user must browse the malicious link. This could be achieved through social engineering or phishing methods, and no other user interaction is required.

Recommendations

It is recommended that the tool definition be altered to remove the iframe component or hard-code the required parameters to display the documentation pages so they cannot be user-controlled. In addition, all user-controllable input should be considered malicious by default, parsed accordingly, and never executed.

Finally, the content security policy should be modified to prevent unsafe-eval and unsafe-inline execution.

2. Stored XSS in Telemetry Viewer (CVE-2025-28380)

The telemetry viewer tool allows users to create, save, and load custom dashboards for easy telemetry visualisation. It includes a list of predefined templates that users can customise for their specific usage. The Web template allows users to include external webpages in iframe windows. Like the previous finding, this allows for including JavaScript code in this field (see Figure 11). This template can then be saved, with execution triggered upon loading by any user who selects it. In addition, the template to load can be defined from a URL parameter, allowing a low-privileged malicious actor to use this as a phishing vector against a user with higher privileges (only applicable in the enterprise version with multiple user accounts).

Figure 11 – XSS is being triggered from the telemetry viewer template loading.

Steps To Reproduce

This can be exploited by creating a new telemetry viewer window and selecting the web template (Figure 12).

Figure 12 – Creating a new Web window template in Telemetry Viewer.

The iframe source can be defined by editing the newly created window (Figure 13).

Figure 13 – XSS code injection in the iframe source.

While this example uses a simple alert to demonstrate the XSS, any JavaScript code can be executed, including the RCE payload shown in section 2.1.2.

Recommendations

As mentioned in section 2.1.3, it is recommended that the tool definition be altered to remove the iframe component altogether. If not possible or desirable, user input should be sanitized to avoid possible injections like the one mentioned. In addition, the CSP should be modified to prevent unsafe-eval and unsafe-inline execution.

3. Remote Code Execution during Plugin Install (CVE-2025-28386)

During a Python plugin installation, the application will install required packages from an included requirements.txt file. This is passed to a pip install binary, called with the trusted hosts flag, to avoid untrusted packages from being installed (Figure 14).

Figure 14 – Plugin auxiliary script to install dependencies.

In addition, the installation is performed from a randomly named temporary folder. However, creating a requirements.txt file to execute a script from anywhere in the system is possible. During installation, the application copies all plugin files into the /gems/gems/<plugin name and version>/ folder. This allows for the creation of a malicious plugin where a script is copied to this folder and called during the Python package installation (Figure 15).

Figure 15 – Obtaining remote code execution from plugin install.

This is executed from the openc3-cosmos-cmd-tlm-api container and exposes all the credentials set within the Docker environment, including credentials for other services running (Figure 16).

Figure 16 – Environment variable dump.

Steps To Reproduce

Two conditions are required for reproduction: a setup.py file that includes the code to be executed must be within a folder copied into a known location (like /gems/gems/), and a requirements.txt file that points to this location (Figure 17).

Figure 17 – Plugin structure and file contents for Code Execution.

Creating and uploading this plugin will execute the setup.py script, creating a reverse shell.

Recommendations

There is no direct fix for this issue. Blocking the application’s ability to install external dependencies of plugins would block one of its main functionalities, and any install functionality can be used to add and execute malicious software. While the application already limits the installation to trusted hosts from the PyPI repository, these are not vetted and can include malicious packages. It is recommended that plugin installation privileges be reserved for administrator users only and routinely audited. This also includes close monitoring of any external connections originating from this container and all running plugins.

4. Arbitrary File Read from Script-API (CVE-2025-28384)

The Script Runner tool allows for the creation and modification of user-defined scripts. By default, these are saved on /plugins/DEFAULT/targets_modified/__TEMP__, and the content can be obtained from the API /script-api/scripts/ endpoint by sending a GET request to /script-api/scripts/<folder>/<name of the script>?scope=<scope> (Figure 18).

Figure 18 – Reading a script using the script-api endpoint.

However, the file path is not sanitized correctly, allowing a user to request any file from the Docker container.

Steps To Reproduce

Any authenticated user can read any arbitrary file within the container by sending a GET request to /script-api/scripts/../../../../../../../../<path to file> (Figure 19).

Figure 19 – Reading an arbitrary file from the host with path traversal.

In addition, since the Docker container is set to run as root by default, there are no restrictions on which files can be read from the host.

Recommendations

It is recommended that all user input be sanitized correctly, including parameters directly obtained from the URL. Furthermore, user file reads/writes should be limited to only the required folders within the host. Finally, it is advised that the Docker container is further restricted from running as root by default.

5. Arbitrary File Read from OpenC3-API (CVE-2025-28382)

Openc3 comes with a Table Manager tool and a binary file editor. It allows managing and editing the binary files according to their definitions [RD-1]. The openc3-api/tables API endpoint is vulnerable to path traversal, which allows an arbitrary file to be read.

Figure 20 – Arbitrary File Read on openc3-api.

Steps To Reproduce

Any authenticated user can read any arbitrary file within the container by sending a GET request to /openc3-api/tables/../../../../../../../../<path-to-file> (see Figure 20). The response from the server contains a base64 encoded list of string values separated by a new-line character that is not encoded. Processing the response with a one-liner Python (see Figure 21) allows us to extract the content of the fetched file (see Figure 22).

Figure 21 – Processing the openc3-api server response.

Figure 22 – Content of an arbitrary file fetched via openc3-api.

Recommendations

It is recommended that all user input be sanitized appropriately, including parameters directly obtained from the URL. Furthermore, user file reads/writes should be limited to only the required folders within the host. Finally, it is advised that the Docker container is further restricted from running as root by default.

6. Arbitrary File Deletion from OpenC3-API (CVE-2025-28382)

Openc3 comes with a Table Manager tool, which is a binary file editor. It allows for managing and editing binary files according to their definitions [RD-1]. Similarly to section 2.5, the openc3-api/tables API endpoint is vulnerable to path traversal, allowing for arbitrary file deletion.

Steps To Reproduce

Any authenticated user can read any arbitrary file within the container by sending a DELETE request to /openc3-api/tables/../../../../../../../../<path-to-file> (see Figure 23). The server returns a 200 OK response, and the file is deleted (see Figure 24).

Figure 23 – Arbitrary File Deletion on openc3-api.

Figure 24 – Deleting an arbitrary file using openc3-api.

Recommendations

It is recommended that all user input be sanitized appropriately, including parameters directly obtained from the URL. Furthermore, user file reads/writes should be limited to only the required folders within the host. Finally, it is advised that the Docker container is further restricted from running as root by default.

7. Arbitrary File Copy from OpenC3-API (CVE-2025-28382)

OpenC3 has a Table Manager tool and a binary file editor. It allows for managing and editing binary files according to their definitions [RD-1]. Similarly to sections 2.5 and 2.6, the openc3-api/tables API endpoint is vulnerable to path traversal, allowing for an arbitrary file copy.

Steps To Reproduce

Any authenticated user can read any arbitrary file within the container by sending a PUT request to /openc3-api/tables/../../../../../../../../<copy-from-path>/save-as/../../../../../../../../<copy-to-path> (see Figure 25). The server returns a 500 Internal Server Error response; however, the requested file was copied to the new location (see Figure 26).

Figure 25 – openc3-api arbitrary file copy endpoint.

Figure 26 – Copying an arbitrary file using openc3-api.

Recommendations

It is recommended that all user input be sanitized correctly, including parameters directly obtained from the URL. Furthermore, user file reads/writes should be limited to only the required folders within the host. Finally, it is advised that the Docker container is further restricted to not run as root by default.

8. Arbitrary File Upload using OpenC3-API and Script-API

Chaining the openc3-api path traversal vulnerability described in section 2.7 and the upload functionality of script-api, it is possible to upload a file to an arbitrary location on the host file system.

Steps to Reproduce

To demonstrate this vulnerability, we’ve prepared a chain of calls that will add a new user with root privileges to the host container. First, we call the script-api to upload the content of the new passwd file (see Figure 27), then we call the openc3-api to replace the /etc/passwd file with the new one (see Figure 28). Again, the server will return a 500 Internal Server Error; however, the file was copied to the destination.

Figure 27 – Upload a new passwd file.

This vulnerability chain results in the system having a new user with root privileges, as shown in Figure 29.

Recommendations

It is recommended that all user input be sanitized correctly, including parameters directly obtained from the URL. Furthermore, user file reads/writes should be limited to only the required folders within the host. Finally, it is advised that the Docker container is further restricted from running as root by default.

Figure 28 – Replace /etc/passwd with the newly uploaded file.

Figure 29 – /etc/passwd before and after execution of the exploitation chain.

9. Credential Leak from Docker Container (CVE-2025-28381)

The Docker configuration included by default sets service credentials as environment variables in all containers. While an effort is made to avoid leaking them to user space in multiple places, some restrictions can be bypassed by any user with access to the application.

Scripts called from the Script Runner application are executed in the openc3-cosmos-script-runner-api container using a set of auxiliary scripts (Figure 30).

Figure 30 – Default scripts included with the script runner for user script execution.

These scripts contain logic to remove secrets and credentials from the environment on execution (Figure 31).

Figure 31 – Code segment unsetting environment variables at runtime.

However, since these are writable to any user executing scripts, they can be directly modified from the web user interface. It is then possible to remove the lines where the variables are unset, reboot the container, and dump all environment credentials (Figure 32).

Figure 32 – Credential and secret dump from Script Runner.

Steps To Reproduce

From within Script Runner, it is possible to directly remove the lines, unset the environment variables, and reboot the container (Figure 33).

Figure 33 – Modifying the script runner file.

From this point on, it is possible to dump all credentials and secrets from the environment.

Recommendations

It is recommended that all unnecessary and unused credentials be removed from all Docker containers. Furthermore, essential system scripts should be read-only and not modifiable by user input. It is also recommended that all user scripts be run from a different and more restricted user. The use of code jails would also significantly improve the application’s security.

All Docker containers appear to be running under the root user, which is not advisable.

10. Insecure Authentication – Use of Clear Text Password (CVE-2025-28389)

Although authentication supports using an authentication token, it also supports clear-text passwords. This approach is less secure since brute-forcing a plain-text password can be much faster than a hash. This is especially true for shorter passwords, like those allowed by OpenC3, which by default provides for passwords as short as 8 characters.

Figure 34 – Use of clear-text password.

Recommendation

The use of clear-text passwords in the application logic should be removed.

11. Insecure Authentication – Service Account (CVE-2025-28388)

When starting COSMOS for the first time, the user is prompted to provide an administrator password. There’s no possibility of creating and managing additional users, which gives a false impression that only one administrative account exists. This is not true since it is possible to log in to the system using the Service Account. There’s no way to manage the password to this account as it is either hardcoded or, by default, set via the environment variable (see Figure 35). This can lead to potential use of the Service Account as a backdoor to the system, especially given that it is possible to leak the defined credentials described in section 2.9.

Figure 35 – Use of service account password.

Recommendation

Currently, the authentication mechanism is straightforward and inconsistent, allowing the user to authenticate with three different passwords: authentication token, clear-text password, and service password. It is recommended that the authentication process be rewritten and split into multiple accounts or that existing authentication and account management functionality be used. At the very least, this use of the Service Account and its password should be documented.