DeepSeek Harness 安全审计实录:四个 PoC 揭露的 Agent 运行时"信任危机"

DeepSeek Harness(DSH)作为开源 Agent 运行时的明星项目,近期被安全研究者披露了四个高危漏洞,涵盖配置注入、沙箱逃逸、权限绕过等攻击面。本文将带你深入这些漏洞的技术细节、端到端攻击链,以及作为开发者和用户该如何应对。


一、从明星项目到安全焦点

DeepSeek Harness(简称 DSH)自开源以来迅速成为 AI Agent 领域的焦点。它基于 Cordis 插件化架构,主打"万物皆插件"------模型适配器、工具注册表、Session 日志、甚至 Agent 主循环本身都可以通过配置组合与替换。短短数周内,生态内就涌现出上千个插件,Star 数突破 15 万。

然而,就在生态高速扩张的同时,安全研究者对 DSH 进行了一次深度架构评审,结果令人警醒:在默认部署下,攻击者可以通过 Prompt Injection 实现从沙箱逃逸到宿主机 RCE 的完整攻击链

官方也在最新版本(v0.1.2-rc.1 / v0.1.3-alpha.2)中更新了安全声明:

"DeepSeek Harness 尚未接受安全审计,沙箱、审批与权限控制不能保证隔离。"

这不是一句客套话,而是有实打实的 PoC 支撑。


二、威胁模型:我们防的是谁?

在深入漏洞之前,先明确 DSH 的威胁模型:

  • 模型是半可信主体:它可能被 Prompt Injection(恶意网页、仓库内容、被 fetch 的文档)诱导
  • read-only 模式的安全承诺:官方宣传该模式适合处理不可信仓库,意味着"只读即安全"
  • 攻击者终极目标:在宿主机执行任意代码,或外泄凭据

基于这个模型,研究者从四个维度展开了攻击面分析。


三、漏洞全景:四个 PoC,三条独立漏洞 + 一条链式利用

3.1 V1:!!js 配置求值 = 加载期同步代码执行

漏洞本质 :DSH 的配置系统支持 !!js YAML tag,会在配置加载时同步执行 JavaScript 代码。这意味着任何能够写入配置文件的角色,都能在系统启动时执行任意代码。

PoC 验证

lua 复制代码
[V1] marker written at config-load time: true
[V1] marker content: "executed-at-config-load"

利用场景

  • 配置投毒 :恶意仓库诱导模型修改 cordis.patch.yml
  • 自修改部署 :DSH 的 demo:cordis 场景下,workspace 与配置目录重叠,写边界被静默闭合

默认部署下的防线 :patch 文件位于 ~/.dsh/profiles/<name>/cordis.patch.yml,默认 workspace-write 权限恰好不包含该目录。但研究者指出:

"没有任何 boot-time 检查保证'已加载的配置目录 ∉ 可写 root'。"

一旦 workspaceRoot 被配到 home 目录、或启用 danger-full-access 模式,这道防线就不攻自破。


3.2 V2:"read-only" 沙箱读穿全盘

漏洞本质:read-only 模式对写操作有严格的 fence,但对读操作完全不设防。

技术细节

  • 进程内 fence(fs-sandbox)只拦截 writeText/editTextreadText 原样透传
  • 进程级 bwrap 配置是 --ro-bind / /------整个宿主文件系统只读挂载进沙箱

PoC 验证

arduino 复制代码
[V2] read of a secret OUTSIDE the workspace under read-only mode:
     "apiKey: dsh-poc-secret-value\n"
[V2] contrast --- write under the same mode denied with code: FS_SANDBOX_DENIED

更危险的插件正门 :动态插件声明 inject: ['fs', 'web'] 时,没有任何 allowlist 检查。这意味着 read-only 模式下,模型可以:

  1. 通过 fs.readText 读取 ~/.ssh/*.env、云凭据
  2. 通过 web 服务将凭据外发

关键是零审批 :默认组合里没有任何 host 侧插件对工具调用发射 ask,"只读安全模式"下模型读凭据是零审批的。


3.3 V4:动态插件 VM 沙箱 exec 逃逸

漏洞本质 :DSH 允许模型通过 cordis_define/cordis_run 工具编写代码并挂载为动态插件,在 node:vm "沙箱"中运行。官方确实做了认真的对抗性设计------拒绝访问 ctx.root/ctx.parent、拒绝 ctx.extend、拒绝返回 Context 的服务......

但漏了一条路径execute(args, exec) 中的 exec 原样透传给了 VM realm 里的模型代码。

typescript 复制代码
// guard.ts:582-584
execute(args, exec) {
  return cloneJson(await rawExecute(args, exec), ...)
}

execToolRunContext 类型,其 exec.agent.ctx真实的运行时 Context。facade 防住了语法面,没防住对象图。

PoC 验证

csharp 复制代码
[V4] dynamic package mounted and running: true
[V4] isError: false
[V4] sandbox-realm tool code retrieved from the host Context: "HOST_SECRET_LEAKED"

3.4 V4b:链式利用 ------ exec 逃逸 → 裸 subprocess → 无约束 RCE

这是整个审计中最具杀伤力的发现:将 V4 与其他漏洞链接,形成端到端攻击链。

为什么这个链成立? 沙箱约束(landlock/seatbelt/bwrap)只存在于 shell 层------bash-sandbox 在调用 ctx.subprocess.spawn 之前包装 argv。但 subprocess seam 自身对约束一无所知,没有任何 sandbox 引用。

这是典型的 enforcement 落点错误:安全策略落在 consumer(bash-sandbox)上,而不是执行点(subprocess seam)上。

PoC 验证

ini 复制代码
[V4b] dynamic package mounted and running: true
[V4b] tool result (isError=false): "spawned-and-exited"
[V4b] unconfined host process wrote marker: true
[V4b] marker content: "unconfined-spawn\n"

端到端攻击链

sql 复制代码
恶意网页 / 仓库内容 / fetch 的文档
        │  prompt injection
        ▼
模型调用 cordis_define + cordis_run(默认组合零审批)
        │
        ▼
VM 沙箱运行模型代码 → execute(args, exec) 拿到宿主 exec
        │
        ▼
exec.agent.ctx.get('subprocess').spawn(...) ------ 无 landlock/seatbelt/bwrap
        │
        ▼
宿主机任意进程执行 → 持久化(patch 文件 + !!js)→ 长期驻留

关键点:场景 A 不依赖任何部署配置失误。V1 单独评估时"默认部署下链是断的"的结论,在 V4b 面前不成立------写边界在插件路径上完全不参与。


四、外部利用场景汇总

# 攻击者入口 链条 影响 默认部署可达性
A Prompt Injection(恶意网页/仓库)→ 模型 cordis_define → V4 exec 逃逸 → V4b 裸 subprocess 宿主 RCE,零文件写入 ✅ 是
B read-only 模式处理不可信仓库 bash cat / fs read 工具 / 插件 inject:['fs','web'] 凭据外泄(.ssh/.env/credentials) ✅ 是
C 配置投毒 模型写 patch 文件 → !!js → HMR 执行 + 每次 boot 重放 持久化 RCE ⚠️ 条件性
D 诱导模型 skill 内容诱导模型走 A/B 路径 同 A/B ✅ 是(放大器)

五、方法论复盘:他们是怎么发现的?

这次评审的流程极具参考价值,按顺序是:

5.1 读架构文档,列"信任假设清单"

先精读 architecture.mdglossarycapability-seams 等文档,目标不是理解怎么用,而是找出系统在哪些地方假设了"模型会配合"。

列出的清单直接变成了候选漏洞:

  • "配置里允许 !!js"------假设了配置文件的写入者可信
  • "read-only 是安全模式"------假设了读不可怕
  • "动态插件运行在受限环境"------假设了 VM 边界真的限制
  • "sandbox 约束 shell 执行"------假设了所有执行都走 shell

5.2 分域并行审计

把代码库分成五个域并行审计:

  1. core loop + session 日志
  2. capability seam
  3. 工具管线与安全
  4. 编排
  5. typert/RPC/wire

关键技巧:画 enforcement 落点图。对每条安全属性,标出它在哪里被强制(provider?consumer?约定?),凡是落在 consumer 或文档语气里的,标记为高风险候选。

5.3 用仓库自己的规则当检测器

DSH 仓库有极其明确的工程规则(CLAUDE.md):

  • "Enforce a decision in the operation that makes it"
  • "Misconfiguration fails loud"
  • "Apply bounds to the complete result"

把这些规则反过来当检测器:找出违反它们的地方,就是漏洞候选。

5.4 先验证原语,再分层 PoC

不直接写大 PoC,先逐个验证最小的"原语假设":

  1. with(ctx)+eval 引擎里 process.getBuiltinModule 可用?
  2. ToolExecutionInput.agent 存在、registry 接受 agent?
  3. loader.create 会触发 interpolate?
  4. writableRoots 的语义与 patch 文件位置的关系?

然后分层 PoC,每层都比上一层更接近真实攻击,且全部用真实代码路径,零 mock

5.5 失败路径也是证据

V4b 第一次尝试(loader.create 带 __jsExpr)失败了------但失败原因本身就是发现:VM-realm 对象过不了宿主 instanceof Object。如实记录失败路径,得到两个收益:

  1. 发现一条"偶然防御",评估它的脆弱性
  2. 转向 subprocess 路线,找到更直接的链

六、修复建议(按优先级)

研究者给出了清晰的修复路线图:

优先级 修复措施 封堵路径
P0 给动态工具 execute 传剥离 agent.ctx 的 facade exec V4 本体 + V4b 整条链
P0 SubprocessRuntime 自身承担 confine 责任:约束在 seam 执行点落地 V4b 结构性根因
P1 动态插件 inject allowlist(白名单收敛),define/run 接入审批管线 V2 插件正门、场景 A 零审批入口
P1 read-only 排除 secret 目录;把默认 approval 真正接进 tools/pre-execute 场景 B 凭据外泄
P2 boot 时校验"已加载配置目录 ∉ writableRoots",相交即 fail loud 场景 C 纵深防御

七、官方回应与社区行动

7.1 官方态度

DSH 团队在 v0.1.2-rc.1 和 v0.1.3-alpha.2 中多次更新安全说明:

"DeepSeek Harness 尚未接受安全审计,沙箱、审批与权限控制不能保证隔离。"

这是一个诚实的声明,但也暴露了早期开源项目的普遍困境:功能迭代速度远超安全审计投入

7.2 社区自救

生态的繁荣也催生了安全意识的觉醒:

  • dshlib(DSH 插件图书馆):社区实验项目,为每个插件提供 CHA2A 认证等级(L0-L4)、安全扫描状态(硬编码密钥/危险命令/数据外传/越权)、OSV.dev 依赖漏洞检测
  • dsh-pentest:面向 DSH 的渗透测试模式插件,支持探索链路、漏洞和资产视图
  • PerryLink/dsh-permission-rules:Claude Code 风格的声明式权限规则,支持有序 allow/deny/ask + 工具/参数/路径匹配
  • dsh-plugin-audit / dsh-plugin-market:插件静态权限审计与市场安全闸门

八、给开发者的安全实践清单

无论你是 DSH 用户还是插件开发者,以下清单都值得贴在显示器旁边:

8.1 安装插件前

  1. 看依赖树package.json 里有没有可疑依赖?体积异常大的要警惕
  2. 看权限诉求:一个"查天气"的插件为什么要声明文件系统写权限?
  3. 看网络出口fetch / axios 调用指向哪里?
  4. 看数据回传:工具结果是否包含本地路径、环境变量、密钥片段?

8.2 运行时隔离

  1. 沙箱兜底:即使插件可疑,只要沙箱规则严格,破坏半径也可控
  2. 权限最小化:只给插件"它需要的",而不是"运行库默认开放的"
  3. 临时挂载测试:新插件先在隔离 workspace 里跑一个任务,观察行为再放行

8.3 可复用检查清单(适用于任何 Agent Harness)

研究者总结的这套方法论,可以套用到任何 Agent 运行时上:

  1. 配置求值面:配置文件里有没有代码求值钩子?谁能写这些文件?
  2. 读/写不对称:安全模式对写做 fence 时,读是否被同等对待?
  3. facade 的对象图:守卫防的是语法还是对象图?被守卫的上下文中是否有对象引用能走回真实运行时?
  4. enforcement 落点:每条安全策略在 provider/执行点强制,还是在 consumer/约定层?
  5. 注入面的下游能力:工具结果裸进上下文时,模型被注入后能触达的最大权限是什么?
  6. 授权语义:审批请求承载了什么?授权粒度是 per-request 还是 per-package?

九、结语

三个漏洞的共同根因可以压缩成一句话:

安全属性的 enforcement 落在了错误的层------配置求值信任了写入者、只读模式信任了"读不可怕"、VM 沙箱防了语法没防对象图、进程约束落在了一个 consumer 而不是执行点。

而链式利用告诉我们:在 Agent Harness 里评估单个漏洞的"可达性"时,必须画到端到端------V1 单看被写边界挡住,V4b 让这道防线根本不在路径上。

对这类系统的防御者,最大的一条建议来自研究者:

把"模型被注入后能走的最远路径"当作系统测试用例来写,而不是当作威胁模型文档来写。

DSH 的架构无疑是先进的------全插件化、可审计、模型无关。但正如一位社区成员所说:"赢了架构这一栏,输了成熟度这一栏。" 安全不是功能完成后的补丁,而是架构设计时的第一性原理。

在 Agent 生态爆发的前夜,DSH 的这次安全审计,或许能为整个行业敲响一记警钟。


参考链接


本文基于公开安全研究报告整理,仅供技术交流与安全防御参考。

相关推荐
LayZhangStrive1 小时前
Prompt - 如何生成贴合我们业务需求的有效prompt
ai·prompt·agent·提示词
苏三说技术1 小时前
再见了EasyExcel,我决定用Apache Fesod
后端
XR1234567881 小时前
医院移动医护零漫游无线网络选型指南
java·后端·struts
SuperHeroWu72 小时前
HarmonyOS Dev Assistant (HarmonyOS开发助手)如何打通元服务开发全流程
ai·agent·harmonyos·vs code·元服务·hbuilderx·assistant
ly76892 小时前
Spring Bean生命周期全流程:从BeanDefinition到销毁
java·后端·spring·bean生命周期·beandefinition·初始化回调
leeyi2 小时前
在 Go 里跑不信任的代码:WASM 沙箱的四道墙(第107篇)
后端
摇滚侠2 小时前
《Spring Boot 3:高级与架构设计》第 1 章 BeanDefinitionRegistry 阅读笔记 3
spring boot·笔记·后端
阿里云云原生2 小时前
记录一次系统认知的升级:当“日志即状态”遇见“对象即真理”,我们如何定义一致性?
agent
大模型真好玩2 小时前
大模型训练全流程实战指南实战篇(十五)——预训练数据治理
人工智能·agent·deepseek