Expression Injection in OpenRemote
Date: 2026-04
Affected: maven/io.openremote:openremote-manager
Attack vector: deserialization
Category: vulnerability-disclosure
Severity: Critical
CVE: CVE-2026-39842
CWE: CWE-917
CWE-94
CVSS: 9.9 (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H)

### Summary The OpenRemote IoT platform's rules engine contains two interrelated critical expression injection vulnerabilities that allow an attacker to execute arbitrary code on the server, ultimately achieving full server compromise. - Unsandboxed Nashorn JavaScript Engine: JavaScript rules are executed via Nashorn's ScriptEngine.eval() with user-supplied script content and no sandboxing, class filtering, or access restrictions. Critically, any non-superuser with the write:rules role can create JavaScript rulesets. - Inactive Groovy Sandbox: The Groovy rules engine has a GroovyDenyAllFilter security filter that is defined but never registered (the registration code is commented out), rendering the SandboxTransformer ineffective. While Groovy rules are restricted to superusers, the absence of sandboxing violates the principle of defense in depth. ### Details #### Attacker-Controllable Source-to-Sink Paths There are two non-superuser and two superuser exploitable attack paths from the REST API entry point to final code execution. (JavaScript × Realm/Asset + Groovy × Realm/Asset) The most critical path is detailed below. Path 1: Unsandboxed JavaScript Expression Injection via Realm Ruleset (Non-Superuser Exploitable) **`RulesetDeployment.java` L368:** ```java Object result = scriptEngine.eval(script, engineScope); ``` The Nashorn JavaScript engine is initialized **without** a `ClassFilter`, allowing `Java.type()` to access any JVM class — including `java.lang.Runtime`


Mitigations:

Architectural layers (MAESTRO):