dsh-plugin-audit
一个可复用的 DSH skill(同时附带可独立运行的初筛脚本),用于在安装任何第三方 DeepSeek Harness 插件 / agent preset 之前,审查它的源码,帮你判断这件事安不安全。
这是仓库的入口说明。skill 本体的触发与执行规则见
SKILL.md;确定性初筛脚本见scripts/scan.mjs;审计报告模板见assets/report-template.md。
为什么安装这个 skill
因为"装第三方插件"这件事,本质是授予它宿主机权限,而这件事没有自动防线替你兜底,只能靠你自己在装之前读一遍源码。这个 skill 把"读一遍源码"变成可复用、有结论的流程:
- 它替你记住前提:装第三方 host 插件 = 授予宿主任意代码执行权,让你不会因为 star 多、进了精选列表、别人说好用就跳过审查。
- 它让审查有抓手:先用脚本把危险信号定位出来,再有针对性地读、判断、给结论,而不是面对一个仓库无从下手。
- 它逼出带证据的结论:按固定模板输出,结论必须有文件 + 行号 + 语义判断,避免一句笼统的"应该没事"。
- 它诚实地划定边界:报告会写明"这只覆盖你给的这份源码",并提醒你锁版本——这是它区别于"自动安全扫描器"的地方,后者常给人虚假的安全感。
怎么安装和使用
安装
把整个 dsh-plugin-audit/ 目录丢进你的技能根目录——~/.agents/skills/ 或 ~/.dsh/skills/。
使用
装任何第三方插件前,对 AI 说:
- "这个插件安全吗?"
- "审查这个 preset / 这个插件目录"
- 直接贴一个插件仓库地址或路径,说"帮我看看能不能装"
AI 会自己跑初筛脚本、读源码、按模板出一份带证据的审计报告(结论是"可装 / 需谨慎 / 不装",附"文件 + 行号 + 为什么")。
也可以只当脚本用(不做语义审查,只做确定性初筛):
node dsh-plugin-audit/scripts/scan.mjs <插件目录>
结果里的每条命中是"值得打开读的疑点",不是结论。
背景:为什么不能随意装插件
安装第三方插件,实质上是把一段未经审查的代码纳入本机的信任范围。就 DSH 的 host 插件而言,这个决定的影响比表面看起来大,原因有三:
1. host 插件与宿主进程同权运行
DSH 的 host 插件通过 import() 加载进运行 DSH 的那个 Node 进程,与 DSH 同权限运行,不经过沙箱,也没有权限清单。这意味着它的代码能够访问本机文件、读取 ~/.dsh/.credentials.yaml、执行命令、发起网络请求——无论它的对外功能看起来多单一。功能是否无害,与它是否具备这些能力,是两件事。
2. 安装链路没有自动化的可信校验
从"插件被发布 → 被收录进列表 → 被推荐 → 你执行安装 → 被加载",整条链路缺乏签名校验、版本锁定和来源完整性检查。awesome-dsh-plugin 这类列表的收录依据是功能与流行度,不代表代码被审计过;star 数、README 质量、他人的使用经历,都不能作为安全证据。
3. 插件是持续生效的,且可被静默更新
host 插件并非一次性脚本:它会在每次会话启动时重新挂载。因此,代码若在后续版本中被修改——无论是上游仓库被攻击、维护者发布了带问题的更新,还是从第三方转存渠道拿到了被改动的副本——都会在下一次安装或更新时生效,而安装者往往无从察觉。
综上,安装第三方 host 插件等于授予它宿主机权限。当前生态不提供自动防线,风险控制依赖安装者自身的判断:在安装前阅读源码,并锁定版本。
背景:攻击方式,以及本 skill 如何拦截
下面的攻击手段按"能被拦截的程度"从高到低排列。
| 攻击方式 | 如何生效 | 本 skill 的拦截 |
|---|---|---|
① !!js 配置任意求值 |
恶意 preset 在 agent.cordis.yml 里写 !!js (()=>{…})(),挂载时被未沙箱化 eval 执行,可读凭据、外发、落持久化 |
scan.mjs 匹配 !!js 及表达式内的 process/getBuiltinModule/createRequire;AI 再读表达式内容,命中即判"不装" |
| ② host 插件直接调用宿主能力 | 恶意包在 apply() 或模块顶层调用 child_process、fs 读凭据、net/http 外发、vm/module 等,因本来就在宿主进程里,无需绕过任何东西 |
scan.mjs 按模块能力抓(require("node:child_process")、from "fs"、import("vm") 都覆盖);AI 读上下文判断用途是否正当 |
| ③ 生命周期脚本投毒 | package.json 的 postinstall/preinstall/prepare 在 pnpm install 时执行恶意代码 |
scan.mjs 匹配这些脚本字段;AI 读脚本内容确认 |
④ curl … | sh 远程执行 |
安装脚本从远端拉取并执行 shell,安装即中招 | scan.mjs 匹配 curl|wget … | sh/bash、eval、bash -c |
| ⑤ 未锁版本的来源漂移 | git clone/git+https 直连最新分支,上游被劫持或更新即换代码 |
scan.mjs 标为 low 信号;报告强制要求锁版本作为补位 |
| ⑥ 混淆 / 动态构造 | process["ch"+"ild_"+"process"]、import("\\x63hild") 等,绕开关键词匹配 |
脚本匹配不到;依赖 AI 语义审查读透整段逻辑;仍是弱项,见下方边界 |
| ⑦ 依赖树深处投毒 | 恶意代码藏在一个无辜名字的依赖包里,随依赖链进入 | 本 skill 默认不深挖 node_modules;靠锁版本 + 只信可信源 |
前五类(①–⑤)中的常见直接形态有确定性信号可抓,脚本先定位、AI 再判定;后两类(⑥⑦)是审计的固有盲区,skill 用"锁版本 + 信任原作者"来兜底,而不是假装能拦。
背景:它检查什么
审计分三层(详见 SKILL.md),各司其职:
| 层 | 谁做 | 检查什么 |
|---|---|---|
| ① 静态预筛 | scripts/scan.mjs |
读 package.json 的 main/module/exports/bin 定真正入口并无条件扫描;按模块能力抓危险信号(child_process/fs/net/http/vm/module/worker_threads,含 node: 前缀与动态 import(),区分 import type 不误报);!!js、生命周期脚本、curl … | sh、.npmrc 是否禁用 lifecycle 脚本、发布物/源码并存检测、锁文件 integrity。附行号 + 上下文。 |
| ② 语义裁决 | AI(SKILL.md) |
读每处命中上下文,裁定 benign/malicious;并进行静态语义还原(识破变量间接/下标/拼接/转义等间接化构造,还原后按真实语义判定)。 |
| ③ 范围外风险声明 | AI(报告模板) | 声明静态与语义均不可及的风险维度:本地 RPC 无鉴权、插件间无隔离、审批社会工程、会话伪造。 |
为什么不能只靠脚本?因为这套威胁正则判不了:正则要么把防御代码误报成危险,要么漏掉混淆代码。所以脚本定位疑点,AI 读懂语义下结论,缺一不可。
一句话原则
第三方 host 插件的安全,唯一依据 = 亲手读过源码 + 锁死版本。精选列表、star、README、别人推荐,都不是安全审计。装之前,先审。
碎碎念
这个发现是因为我的插件把我的新会话崩了
License
MIT
No comments yet. Be the first to write one.