
Critical remote code execution vulnerability in OpenRemote's Rules Engine allows authenticated users with `write:rules` role to execute arbitrary code on the server with root privileges.
Critical remote code execution vulnerability in OpenRemote's Rules Engine allows authenticated users with write:rules role to execute arbitrary code on the server with root privileges.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H| Aspect | Details |
|---|---|
| CVE ID | CVE-2026-39842 |
| GHSA ID | GHSA-7mqr-33rv-p3mp |
| Vulnerability Type | Code Injection / Expression Language Injection |
| CVSS Score | 10.0 (Critical) |
| CWE | CWE-94, CWE-917 |
| Product | OpenRemote |
| Affected Versions | <= 1.21.0 |
| Fixed Version | >= 1.22.0 |
| Authentication Required | Yes |
| Privilege Level Needed | write:rules role (non-superuser) |
| Vulnerable Endpoints | POST /api/{realm}/rules/realm, POST /api/{realm}/rules/asset |
| RCE Execution Level | root |
| Exploitability | High |
| Complexity | Low |
| Discovery Date | 2026 |
OpenRemote is an open-source IoT platform for building smart buildings, cities, and industries. It provides device management, automation rules, analytics, and integrations for the Internet of Things ecosystem.
Internet / Network
|
┌────────┴────────┐
v v
┌──────────────┐ ┌──────────────┐
| Web Browser | | Mobile App |
└──────────────┘ └──────────────┘
| |
└────────┬────────┘
v
┌──────────────────┐
| OpenRemote API |
| (REST/WebSocket) |
└────────┬─────────┘
v
┌──────────────────┐
| Manager Service |
| (Port 8080) |
└────────┬─────────┘
|
┌────────────────────┼────────────────────┐
| | |
v v v
┌──────────┐ ┌──────────┐ ┌──────────────┐
| Rules | | Asset | | Notification |
| Engine | | Storage | | Service |
└──────────┘ └──────────┘ └──────────────┘
| |
v v
┌──────────────────────────────────┐
| PostgreSQL / Timescale Database |
└──────────────────────────────────┘
The vulnerability stems from two critical flaws in OpenRemote's Rules Engine:
Flaw 1: Unsandboxed Nashorn JavaScript Engine
The Java Nashorn JavaScript engine is used to evaluate user-supplied rule expressions without any sandboxing, security manager, or ClassFilter restrictions. This allows attackers to access Java classes directly from JavaScript context.
Flaw 2: Disabled Groovy Sandbox
The Groovy script engine had a GroovyDenyAllFilter registered to prevent code execution, but this filter registration was commented out in the codebase. Only Groovy enforcement existed at the API level (RulesResourceImpl.java:262), but JavaScript had no restrictions.
RulesResource.java (lines 153-158)
|
> POST request handler for rule creation
|
v
RulesetDeployment.java (line 368)
|
> scriptEngine.eval(ruleExpression)
|
v
Nashorn Engine
|
> No ClassFilter / SecurityManager
> Java.type() accessible
> Runtime.exec() available
The vulnerability affects authenticated users with the write:rules role. The authorization check at RulesResourceImpl.java:262 only blocks Groovy for non-superusers:
if (!isUserSuperuser && isGroovy) {
throw new UnauthorizedException("Groovy rules not allowed");
}
This means:
Additionally, multi-tenant isolation can be bypassed via reflection on the assetStorageService to access other realms' data.
┌─────────────────────────────────────────────────────┐
| 1. Attacker authenticates with write:rules role |
└─────────────────────────────────────────────────────┘
|
v
┌─────────────────────────────────────────────────────┐
| 2. POST /api/{realm}/rules/realm with JS expression|
└─────────────────────────────────────────────────────┘
|
v
┌─────────────────────────────────────────────────────┐
| 3. Expression passes validation (no checks) |
└─────────────────────────────────────────────────────┘
|
v
┌─────────────────────────────────────────────────────┐
| 4. RulesetDeployment.java calls scriptEngine.eval() |
└─────────────────────────────────────────────────────┘
|
v
┌─────────────────────────────────────────────────────┐
| 5. Nashorn Engine executes JavaScript payload |
└─────────────────────────────────────────────────────┘
|
v
┌─────────────────────────────────────────────────────┐
| 6. Java.type("java.lang.Runtime") access granted |
└─────────────────────────────────────────────────────┘
|
v
┌─────────────────────────────────────────────────────┐
| 7. Arbitrary command execution as root |
└─────────────────────────────────────────────────────┘
Step 1: Obtain write:rules Credentials