一条exec穿透了Agent沙箱:DeepSeek Harness逃逸链拆解

一条exec穿透了Agent沙箱:DeepSeek Harness逃逸链拆解

TL;DR 四行速览

🔹 事件:DeepSeek 8 月开源的 Agent 运行框架 DeepSeek Harness(dsh),其动态包沙箱存在逃逸链 QVD-2026-52646——模型写的一段代码,可以从 node:vm 沙箱里直接摸到宿主进程执行权;

🔹 根因:不是沙箱没写,而是一个对象忘了脱敏——execute(args, exec) 把宿主完整运行时上下文 exec 原样递进沙箱,沙箱代码顺着 exec.agent.ctx 拿到整个服务图入口,直至 subprocess 起进程;

🔹 本号实测:我们在 master 最新源码上复核了全部关键断点(guard.ts:582 透传、façade 只包 apply),并用 node:vm 复刻了同构 seam 演示——沙箱内读出机密、以宿主 uid 起进程,全程无 require;

🔹 启示:对一切「插件生态 + 模型可写代码」的 Agent 框架,「上下文对象跨信任边界必须投影」是条铁律——这条链对所有自研 Agent 平台同样成立。

一、背景:当「一切皆插件」遇上「模型自己写插件」

DeepSeek Harness 是 DeepSeek 8 月中开源的 Agent 运行框架,上线不到一周 GitHub 星标破五万,现在的定位是「给只会聊天的 AI 装上手脚」:模型负责推理,框架负责让它真正操作本地文件、终端、网页。它最有辨识度的架构选择叫 everything is a plugin——模型适配、工具注册、沙箱策略、会话存储全部是插件,由 Cordis 微内核统一装配。

这套架构里有个很「性感」的能力:动态包(dynamic package)。模型在对话里觉得缺个工具,可以现场写一段 TypeScript,框架把它丢进 node:vm 沙箱求值,注册成插件直接用——AI 给自己写插件、自己装上、自己调用,闭环非常丝滑。开源社区围绕它已经长出了插件市场和三方生态,deepseek-plugin.org 这类目录站收录的插件数以百计。

问题也随之而来:三方插件、别人分享的配置组合包、模型被诱导自己生成的动态包——这三类代码的信任级别天差地别,但在框架眼里它们都走同一条执行路径。8 月 13 日有研究者向项目方上报了沙箱逃逸链并获得 QVD 编号,9 月 16 日先知社区作者 P3nc1l 发布深度分析:打穿沙箱的不是什么奇技淫巧,而是 一个跨信任边界时忘记脱敏的对象。本号在最新 master 源码上复核了全部关键断点,本文把这条链完整拆给各位看。

一条exec穿透了Agent沙箱:DeepSeek Harness逃逸链拆解

▲ 信源:先知社区原文(P3nc1l,2026-09-16),本篇核心事实出自该文

二、完整攻击链:七步,从一个对象引用到宿主 RCE

一条exec穿透了Agent沙箱:DeepSeek Harness逃逸链拆解

▲ V4b 攻击链全景:三个入口、七步利用、落地影响(依据原文 + 本号源码复核整理)

先给全景。攻击入口有三类:装了恶意三方插件、加载了被人做过手脚的配置组合包、或者模型在对话里被诱导自己写了段带私货的动态包。三类入口殊途同归——不可信代码最终都进入了 execute(args, exec) 这条调用链。

STEP 1-2:沙箱本身没破,破的是「递东西的方式」

node:vm 沙箱该做的都做了:注入的全局只有 harness/console/btoa/atob/TextEncoder 这几个,require、fetch、定时器全是抛错陷阱,process 压根不存在。沙箱文件的注释自己都写着「is not containment」——它管全局对象,不承诺对抗恶意代码。真正的问题发生在宿主回调动态代码的时刻:动态工具的定义签名是 execute(args, exec),宿主在调用它时,把一份完整的运行时上下文 exec 当参数原样递了进去。

本号在 GitHub master 分支上核对了这处代码(packages/extensions/cordis-host-runner/src/guard.ts 第 582-584 行):宿主侧对工具返回值做了跨 realm 的 cloneJson 克隆——防的是沙箱对象泄漏到宿主;但对传入的 exec什么都没做,原样透传。防线只修了一半。

一条exec穿透了Agent沙箱:DeepSeek Harness逃逸链拆解

▲ master 分支 guard.ts:582:execute 只克隆返回值,exec 参数原样透传(本号源码复核)

STEP 3-4:同一个对象,两种待遇

exec 这个对象里装着一次工具调用的运行时状态,其中有个 agent 字段。有意思的是 同一个 exec 里的 parent 字段被特意做成了不透明 token——设计注释明说是为了让观察者拿不到外层活的执行对象。说明写这段代码的人完全懂「活对象不能外借」的道理,parent 享受了待遇,agent 却没有:运行时它挂着 options/session/inbox 和一个完整的 ctx。而公开类型契约里,Agent 被声明为只有 { id }——按文档写代码的人根本想不到运行时背后还有这一坨。

更要命的是 agent.ctx 的真实身份:它不是降权视图,而是完整的 Cordis Context + 一层作用域标签——get/provide/plugin/effect/on/emit 全套动词,背后就是宿主的整个服务图。架构注记里写得直白:所有 agent 共享一个服务图,作用域只影响注册可见性,「不是权限系统」。沙箱代码拿到它,等于拿到服务图入口。

STEP 5-7:绕开所有包裹层,直连进程服务

正常路径下,模型要执行命令得走 bash 工具,那里有 ctx.sandbox.confine 做的 bwrap/landlock/seatbelt argv 包裹。但 agent.ctx 到手后不必走正门:ctx.get('subprocess') 直接取到宿主的子进程服务,spawn 一个宿主进程。这个服务的设计注释写着「它没有配置:一切约束和限制都由调用方在 spec 里传入」——正门调用方会自觉带约束,这条缝上的调用方是攻击者,自然什么都不带。三层防线中,vm 沙箱被 exec 透传绕开,bash 沙箱被直连服务绕开,只剩进程树继承的外层文件策略还在苦撑。

一条exec穿透了Agent沙箱:DeepSeek Harness逃逸链拆解

▲ 三层防线对照:为什么「读/执行/网络」全通、只有「写」受限(本号依据原文整理)

原文作者实测到 9 月 15 日:0.1.5-rc.2 源码版和 0.1.6-alpha.1 npm 发布版上 PoC 均实机复现,最新 master 的关键路径静态核对无变化——披露一个月后漏洞仍在。落地上,读 ~/.dsh 机密、拉起宿主进程、网络外传全部可行;唯一被拦的是「写工作区外文件」,而拦它的是外层文件策略(只读挂载),不是这条链上的任何机制——换成 danger-full-access 模式或没有这层策略的部署,写与持久化同样成立。

三、本机实测:50 行代码复刻这条缝

光看别人的复现不过瘾,本号用 50 行 Node 脚本复刻了这条 seam 的最小同构演示:宿主侧构造带 agent.ctx 的 exec(挂着机密读取和子进程两个「服务」),node:vm 沙箱全局清空,然后按 guard.ts 的方式把 exec 原样递进去。

一条exec穿透了Agent沙箱:DeepSeek Harness逃逸链拆解

▲ 本号 node:vm 同构演示实测:沙箱内读出机密、以宿主 uid=1000 起进程(2026-09-27)

结果一目了然:沙箱代码先打印 callId(证明拿到了真实 exec),随后顺着 exec.agent.ctx 读出宿主「机密」,再调 subprocess 服务以宿主真实 uid=1000 执行了 id 命令——全程没有 require,没有 process,沙箱全局干净得能照镜子,但宿主权限已经到手。这就是「对象引用跨 realm」的分量:vm 沙箱隔离的是全局作用域,管不住宿主亲手递进来的参数。

对照组也值得一看:如果把 exec 里的 agent 字段换成投影后的最小对象(只留 id),同样的沙箱代码立刻在取 ctx 一步抛 undefined——印证了原文的修复方向:不是拆掉 agent.ctx,而是在跨边界传参前把它剥掉。低级失误不低级在于,它提醒所有框架作者:每一个跨信任边界传的对象,都要问一句「这份能力清单经过审计吗」。

四、红队视角:三类入口怎么用,蓝队看什么信号

把视角切回攻击方。这条链在实战中的三类入口,威胁模型完全不同:三方插件是最现实的供应链入口——插件市场没有审批管线,装一个「看似正常」的格式化工具就够;配置组合包更阴,分享一个带动态代码的 workspace 配置,目标加载即中招;模型被诱导则是纯 prompt 注入玩法——在网页、文档里埋指令,让目标用户的 dsh Agent「给自己写个工具」,代码里的私货跟着进沙箱。

检测侧(蓝队视角)值得盯三类信号:其一,dsh 宿主进程突然 spawn 了不认识的子进程——正常工具都会经 bash 沙箱包裹,直连 subprocess 起的进程没有 confine 痕迹;其二,~/.dsh/ 目录外的异常读取——特别是 settings.yaml 这类带 API Key 的文件被非预期进程打开;其三,网络侧,dsh 进程直连外部域名(沙箱里 fetch 明明是抛错陷阱,有外传说明走的是宿主服务)。企业内如果放开了本地 Agent 工具,这三条建议进基线。

修复方向上,原文给出的最小修法本号完全认同:投影 exec(至少剥掉 agent.ctx,或把 agent 降级成声明的 { id })、subprocess 缝自带约束(把「调用方自觉」变成 seam 契约)、动态包接入审批管线、以及补一条「沙箱代码永远拿不到 Context」的不变量测试。截至本文写作,上游未发布修复,防守方只能自救:别装来路不明的插件、别加载陌生配置、动态包功能默认关。

五、原文致谢与参考

本文核心方法论改编自先知社区作者 P3nc1l 的《一条 exec 如何穿过沙箱:DeepSeek Harness QVD-2026-52646 漏洞与安全模型分析》(2026-09-16 发布)。原文从复现一路溯源到 Cordis 架构注记,三条证据链(披露存档、版本时间线、源码逐字摘录)齐整,是近期罕见的框架安全分析范本,推荐配合阅读。

本号独立工作:master 分支 guard.ts / sandbox.ts / subprocess-local / runtime-types 四处关键源码复核;node:vm 同构 seam 演示复刻与实测;攻击链/三层防线图重绘。框架仓库:deepseek-ai/deepseek-harness。

一条exec穿透了Agent沙箱:DeepSeek Harness逃逸链拆解

▲ 信源:DeepSeek Harness 官方仓库(master),本号源码复核对象

⚠️ 免责声明:本文仅用于防御研究与授权测试场景的技术学习,请遵守《网络安全法》及相关法律法规,未授权测试一律不做。

 

分享到: 文章二维码
© 版权声明

暂无评论

您必须登录才能参与评论!
暂无评论...