Heym 工作流 RCE 漏洞深度剖析:CVE-2026-67544 从 playwrightCode 注入到 root 权限沦陷的应急响应

【Heym 工作流 RCE 漏洞】深度剖析 CVE-2026-67544:Heym 工作流引擎因 playwrightCode 字段未做沙箱与 AST 校验,导致任意认证用户可远程代码执行。本文从漏洞原理、攻击链路、CVSS 8.8 风险评级到 0.0.71 修复方案与生产加固实践,给出完整应急...

导语:Heym 工作流 RCE 漏洞(CVE-2026-67544)是近期自托管自动化平台中最值得警惕的高危缺陷之一——一个 freshly registered 的普通账号,仅凭往 Playwright 节点的 playwrightCode 字段塞入一段 Python 字符串,就能让后端以 root 身份执行任意代码。本文以架构师视角完整复盘这条从「字段注入」到「主机沦陷」的攻击链路,并给出可直接落地的应急与加固方案。

🎯 核心技术Heym 工作流引擎 / Playwright 节点
⚡ 风险等级High · CVSS 8.8
🚀 修复版本Heym 0.0.71
📐 Heym 工作流 RCE 漏洞攻击链路与纵深防御全景
企业级架构规范

flowchart TD
    subgraph 接入层 ["表现层与接入网关 (Client & Gateway Tier)"]
        A["任意已认证用户 (含新注册账号)"] --> B["工作流编辑器 / API 提交"]
        B --> C["Playwright 节点 playwrightCode 字段"]
    end
    subgraph 规则层 ["校验与编排层 (Validation & Orchestration Tier)"]
        C --> D{"是否存在 AST 校验 / 沙箱 / 角色门禁?"}
        D -->|"否 (0.0.71 之前)"| E["字符串直接落盘为临时 .py 文件"]
        D -->|"是 (0.0.71 修复后)"| F["拒绝执行并记录审计日志"]
    end
    subgraph 执行层 ["后端执行引擎 (Execution Tier)"]
        E --> G["subprocess.Popen([sys.executable, script_path])"]
        G --> H["以服务进程用户身份执行 (默认 Docker 为 root)"]
    end
    subgraph 影响层 ["主机与数据面 (Impact Tier)"]
        H --> I["任意命令执行 / 凭据窃取"]
        H --> J["横向移动 / 持久化后门"]
        H --> K["业务数据与密钥泄露"]
    end
  
图 1: Heym 工作流 RCE 漏洞从 playwrightCode 注入到 root 权限执行的完整链路,以及 0.0.71 引入的校验门禁阻断点。

一、漏洞速览:Heym 工作流 RCE 漏洞的核心事实

CVE-2026-67544 的官方描述非常克制,但信息量极大:Heym 在自托管基础设施上构建并运行 agentic systems 与业务流程自动化,其工作流引擎接受 Playwright 节点 playwrightCode 字段中的任意 Python 代码字符串,将其写入临时 .py 文件后,通过 subprocess.Popen([sys.executable, script_path]) 直接执行,全程没有沙箱、没有 AST 校验、没有角色门禁。

评估维度 详情 架构影响
CVE 编号 CVE-2026-67544 需纳入资产漏洞台账
严重等级 High · CVSS 8.8 高优先级修复
受影响版本 < 0.0.71 默认 Docker 部署风险最高
攻击前提 任意已认证账号(含新注册) 认证边界形同虚设
执行身份 服务进程用户,默认 Docker 为 root 主机完全沦陷
修复版本 0.0.71 升级即阻断主链路
🚨 严重隐患告警

CVSS 8.8 意味着这是「可远程利用、低复杂度、高机密性与完整性影响」的典型组合。更危险的是攻击门槛极低——不需要管理员权限,不需要社工,注册一个账号即可。任何暴露在公网、允许自助注册的 Heym 实例都应视为已被入侵的高危候选。

二、攻击链路拆解:从字段注入到 root 执行

2.1 第一步:认证边界被「新注册账号」击穿

很多团队在评估 RCE 漏洞时会下意识认为「需要管理员权限」,从而降低优先级。CVE-2026-67544 恰恰相反:官方明确指出 Any authenticated user — including a freshly registered account。这意味着只要实例开放注册,攻击者从零到 RCE 的路径只有「注册 → 创建工作流 → 添加 Playwright 节点 → 填入 payload → 运行」五步。

2.2 第二步:playwrightCode 字段的信任错位

Playwright 节点的设计初衷是让用户自定义浏览器自动化脚本,因此 playwrightCode 天然被当作「用户可控的代码内容」。问题在于,工作流引擎把这个字段当成了「可信代码」而非「不可信输入」——它没有区分「配置数据」与「可执行代码」的边界,直接把字符串落盘为 .py 文件。

2.3 第三步:subprocess.Popen 的裸执行

真正致命的是执行方式:subprocess.Popen([sys.executable, script_path])。这行代码等价于「用当前 Python 解释器运行一个用户完全可控的脚本」,且继承父进程的全部权限与环境变量。在默认 Docker 部署中,服务进程以 root 运行,于是攻击者拿到的就是一个 root shell 的等价能力。

# 漏洞版本中的执行逻辑示意(非官方源码,仅用于说明攻击面)
import subprocess
import sys
import tempfile

def run_playwright_node(playwright_code: str):
    # 1. 用户可控字符串直接落盘
    with tempfile.NamedTemporaryFile(suffix=".py", delete=False, mode="w") as f:
        f.write(playwright_code)
        script_path = f.name

    # 2. 无沙箱、无 AST 校验、无角色门禁
    # 3. 以服务进程身份(默认 Docker 为 root)执行
    proc = subprocess.Popen([sys.executable, script_path])
    proc.wait()
⚠️ 生产避坑风险

不要以为「内网部署就安全」。自托管自动化平台往往持有大量业务系统凭据(数据库密码、API Token、SSH Key),一旦 RCE 成功,攻击者可以立即读取环境变量与配置文件,完成横向移动。内网不是安全边界,只是延迟被发现的时间。

三、根因分析:为什么这类漏洞在 Agent 平台反复出现

从架构视角看,Heym 工作流 RCE 漏洞不是孤例,而是「低代码/Agent 平台」这一类系统的结构性风险。它们天生需要执行用户定义的逻辑,而「执行用户逻辑」与「执行任意代码」之间只隔着一层薄薄的抽象。

  • 信任边界模糊:把「工作流配置」与「可执行代码」混在同一个数据模型里,字段级权限缺失。
  • 执行模型过于直接:用 subprocess 起独立解释器,绕过了应用层所有拦截器与审计钩子。
  • 默认配置不安全:Docker 默认以 root 运行,放大了任何代码执行缺陷的后果。
  • 缺少纵深防御:没有 AST 白名单、没有 seccomp/AppArmor、没有网络出口限制,单点失守即全线失守。
💡 架构核心决策

对于任何「允许用户提交可执行逻辑」的平台,必须默认假设「用户输入 = 恶意代码」。正确的架构不是「校验字符串」,而是「把执行放进不可信域」:独立容器、只读文件系统、无网络、非 root 用户、资源配额、执行超时。校验只能降低概率,隔离才能兜住底线。

四、应急响应:四步完成 Heym 工作流 RCE 漏洞处置

4.1 第一步:资产盘点与暴露面收敛

立即梳理所有 Heym 实例,确认版本号是否低于 0.0.71。对于公网暴露且开放注册的实例,优先下线或加访问控制,再谈修复。

4.2 第二步:升级到 0.0.71 并验证

官方已在 0.0.71 中修复该问题。升级后务必回归验证 Playwright 节点的正常功能,确认修复没有破坏合法工作流。

点击展开:升级命令与修复后验证脚本
# 1. 备份当前配置与数据卷
docker compose down
tar -czf heym-backup-$(date +%F).tar.gz ./data ./config

# 2. 拉取并升级到 0.0.71
docker compose pull
docker compose up -d

# 3. 确认版本
docker compose exec heym heym --version

# 4. 验证 Playwright 节点功能正常(使用合法脚本)
# 在 UI 中创建一个最小工作流,确认执行成功且无异常日志
docker compose logs --tail=100 heym | grep -i "playwright"

4.3 第三步:入侵痕迹排查

如果实例在修复前长期暴露,必须假设可能已被利用。重点排查临时目录中的可疑 .py 文件、异常子进程、非预期的网络连接与新增的持久化项。

# 查找近期创建的临时 Python 脚本
find /tmp /var/tmp -name "*.py" -mtime -30 -ls 2>/dev/null

# 检查异常子进程与网络连接
ps auxf | grep -E "python|playwright" | grep -v grep
ss -tunap | grep -E "ESTABLISHED|LISTEN"

# 检查容器内新增用户与计划任务
getent passwd | tail -20
crontab -l 2>/dev/null; ls -la /etc/cron.* 2>/dev/null

# 检查环境变量是否被外带(重点看是否有异常外联)
docker compose exec heym env | grep -iE "token|secret|password|key"

4.4 第四步:凭据轮换与加固

一旦确认或高度怀疑被利用,立即轮换 Heym 实例可访问的所有凭据:数据库密码、API Token、SSH Key、云厂商 AK/SK。凭据轮换的优先级高于日志分析,因为攻击者可能已经完成数据外带。

🚨 严重隐患告警

不要在受感染的宿主机上直接做取证分析后再重建——攻击者可能已植入后门。正确顺序是:隔离网络 → 快照取证 → 重建实例 → 轮换凭据 → 复盘。任何在「可能已被 root 控制」的机器上继续运行业务的行为都是不可接受的。

五、纵深防御:让 Heym 工作流 RCE 类漏洞不再致命

补丁解决的是「这一个」漏洞,架构解决的是「这一类」漏洞。以下加固措施建议作为自托管 Agent 平台的标准基线。

防御层级 传统做法 推荐加固方案 架构收益
进程权限 Docker 默认 root 运行 非 root 用户 + 只读根文件系统 爆炸半径收敛
执行隔离 subprocess 直接执行 独立容器 / gVisor / Firecracker 微虚机 内核级隔离
代码校验 无校验 AST 白名单 + 禁用危险模块导入 降低利用概率
网络出口 默认全通 执行域无外网 + 出站白名单 阻断数据外带
角色门禁 任意认证用户可用 Playwright 节点仅管理员可用 + 审计 最小权限原则
资源限制 无限制 CPU/内存配额 + 执行超时 防资源耗尽

5.1 最小权限容器配置示例

即使暂时无法引入微虚机隔离,也应先把容器权限压到最低。以下 compose 片段可直接作为基线参考。

services:
  heym:
    image: heym:0.0.71
    user: "10001:10001"          # 非 root 运行
    read_only: true               # 只读根文件系统
    tmpfs:
      - /tmp:size=64m,noexec,nosuid  # 临时目录禁止执行
    cap_drop:
      - ALL                       # 丢弃全部 Linux capabilities
    security_opt:
      - no-new-privileges:true
    networks:
      - internal_only             # 仅内网,无默认外网出口
    deploy:
      resources:
        limits:
          cpus: "2"
          memory: 2g

networks:
  internal_only:
    internal: true
⚠️ 生产避坑风险

noexec 挂载 /tmp 能阻断「落盘即执行」的经典路径,但攻击者仍可通过 python -c 或内存加载绕过。因此挂载选项只是纵深防御的一层,不能替代真正的执行隔离。不要把「加了 noexec」当成「已经安全」。

5.2 代码级校验的正确姿势

如果业务确实需要允许用户提交受限脚本,AST 校验可以作为第一道过滤网,但必须明确它的定位:降低误用与低阶攻击,不承担对抗高级攻击者的职责。

import ast

FORBIDDEN_MODULES = {"os", "sys", "subprocess", "socket", "shutil", "ctypes", "importlib"}
FORBIDDEN_CALLS = {"eval", "exec", "compile", "__import__", "open"}

class SafetyVisitor(ast.NodeVisitor):
    def visit_Import(self, node):
        for alias in node.names:
            if alias.name.split(".")[0] in FORBIDDEN_MODULES:
                raise ValueError(f"禁止导入模块: {alias.name}")
        self.generic_visit(node)

    def visit_ImportFrom(self, node):
        if node.module and node.module.split(".")[0] in FORBIDDEN_MODULES:
            raise ValueError(f"禁止导入模块: {node.module}")
        self.generic_visit(node)

    def visit_Call(self, node):
        if isinstance(node.func, ast.Name) and node.func.id in FORBIDDEN_CALLS:
            raise ValueError(f"禁止调用: {node.func.id}")
        self.generic_visit(node)

def validate_user_code(code: str) -> None:
    tree = ast.parse(code, mode="exec")
    SafetyVisitor().visit(tree)
💡 架构核心决策

AST 白名单必须与「执行隔离」组合使用,且校验逻辑应放在独立进程或独立服务中,避免校验器本身被绕过。更重要的是:校验失败必须记录完整审计日志(用户、工作流 ID、原始代码哈希),这是事后溯源的关键证据。

六、总结:从 Heym 工作流 RCE 漏洞看 Agent 平台的安全基线

CVE-2026-67544 给所有自托管 Agent 与低代码自动化平台敲响了警钟:当平台的核心能力就是「执行用户定义的逻辑」时,安全边界不能建立在「用户不会写恶意代码」的假设上。Heym 工作流 RCE 漏洞的本质,是把「不可信输入」当成了「可信代码」,并用最直接的方式执行它。

对架构师而言,可复用的结论有三条:第一,任何代码执行能力都必须运行在独立、非 root、无外网、有配额的不可信域中;第二,字段级权限与角色门禁要在数据模型层就设计好,而不是事后补;第三,默认配置必须安全,因为绝大多数生产事故发生在「没人改过默认值」的实例上。补丁会过时,基线不会。

原文出处与权威溯源声明:
本文核心技术背景源自海外一线技术研究:
NVD – CVE-2026-67544 官方漏洞详情

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注