Security: workflow tool vm escape via injected host-realm functions (user-privilege file/network access, sandbox bypass) #243
Mengxun326
started this conversation in
General
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Summary
The workflow tool (
@deepseek-ai/dsh-workflow-worker-thread) executes model-generated workflow scripts inside a Nodevmcontext created from an empty object (vm.createContext({})), but injects host-realm closures (agent,parallel,pipeline,phase,log) as globals. Because those functions are objects from the worker realm,agent.constructoris the worker realm'sFunction. A one-line expression therefore escapes the vm into the worker thread:The worker is a normal Node worker thread: it is not covered by the file sandbox (bwrap / Landlock / Seatbelt / Windows ACL), its global
fetchis unrestricted, andprocess.getBuiltinModule()(Node >= 22.3) providesfs,child_process,net, etc. Environment scrubbing (workerSpawnEnv()keeps onlyTMP/TEMP) does not help, because file and network access remain.Affected version / location
@deepseek-ai/dsh-workflow-worker-thread0.1.0-rc.6(published npm artifact; same pattern onmasterat time of writing)lib/worker.cjs,WorkflowExecutionconstructor (around lines 258–284):@deepseek-ai/dsh-code-runtime-worker-thread/lib/worker.cjsexecutes injected code vianew AsyncFunction(...namespaces, "console", "'use strict';\n" + code)(...)directly in the worker realm.processis a worker global there, soprocess.getBuiltinModule('fs')is reachable without any escape step. (There the trust level of code authors is higher, but it is the same exposure class.)Reproduction
Minimal PoC replicating the harness's own worker configuration (scrubbed env,
execArgv: []). Harmless: it only reads the public Windows fileC:\Windows\win.inito prove filesystem reach, and performs no network I/O.Verified on Node
v24.19.0(Windows 11), with the same worker options the harness uses: the escaped code readC:\Windows\win.inisuccessfully, and the worker'sprocess.envcontained only the scrubbedTMP/TEMP(so the env scrub works — it just does not stop the escape).In the real tool, the same expression placed at the top of any workflow script body gives the script:
$DSH_HOME/.credentials.yaml), SSH keys, browser profiles;fetch(direct exfiltration channel);process.getBuiltinModule('child_process').Impact
lib/types/realm.js— "the vm is not a security boundary. The worker provides host-loop isolation and forced termination, not hostile-value containment" — understates the exposure: the worker also provides a one-line path to host filesystem and network, not merely loop protection.Suggested fixes
Any one of these addresses the root cause:
vm.compileFunction, or pre-evaluated wrapper functions that live in the context) so that theFunctionreachable from script values is the context realm'sFunction, not the worker realm's.ctx.sandbox.confine) or a dedicated restricted worker, so filesystem/network effects are bounded even if the vm is escaped.process.getBuiltinModule, replace globalfetchwith a policy-restricted implementation, and enablevmcodeGenerationrestrictions.dsh-code-runtime-worker-thread, run injected programs under the same process-level confinement.Severity
High — local, user-privilege RCE from the workflow tool that bypasses the sandbox. No remote pre-auth vector: the web API stays loopback-only, so exploitation requires the agent (or an injected prompt) to actually invoke the workflow tool.
Disclosure note
Filed publicly because the repository has no
SECURITY.mdor private reporting channel. The PoC above is deliberately read-only and non-exfiltrating. Happy to open a PR if maintainers prefer a particular fix approach.中文摘要
结论:
workflow工具用vm.createContext({})运行模型生成的脚本,却把宿主(worker 线程)realm 的闭包函数(agent/parallel/pipeline/phase/log)直接注入为全局变量。因此脚本里一行代码即可逃逸 vm:agent.constructor是 worker realm 的Function,可拿到 worker 的process,进而使用process.getBuiltinModule('fs' | 'child_process' | 'net')与全局fetch。worker 线程不受文件沙箱(bwrap / Landlock / Seatbelt / Windows ACL)约束,环境变量清洗(仅 TMP/TEMP)也挡不住文件与网络通道。影响:恶意或经提示注入诱导的模型一旦调用 workflow 工具,即可获得当前用户权限的任意文件读写(含
$DSH_HOME/.credentials.yaml中的 API 密钥、SSH 私钥)、无限制外联(worker 全局fetch)与任意命令执行,完全绕过文件沙箱。验证:已在 Node v24.19.0 / Windows 11、与 harness 相同的 worker 配置(scrubbed env、
execArgv: [])下用最小 PoC 复现(仅读取公开系统文件C:\Windows\win.ini以证明文件系统可达,无网络外传),PoC 见上文。修复建议:
vm.compileFunction在 vm realm 内部构造钩子,或经 postMessage 式异步 RPC 暴露;ctx.sandbox的进程级隔离;process.getBuiltinModule、替换全局fetch、开启codeGeneration限制作为纵深防御;dsh-code-runtime-worker-thread用new AsyncFunction直接执行注入代码,暴露面同源,建议一并处理。披露说明:仓库未提供 SECURITY.md 或私有上报渠道,且 issues 已关闭,故按 CONTRIBUTING 指引在本 Discussions 公开提交;PoC 特意设计为只读、不外传。欢迎维护者指定修复方向,可随时配合提交补丁。
All reactions