dsh-plugin-audit
Agent Skill for DeepSeek Harness (DSH):装第三方插件前的静态安全审计 —— 扫出 eval、patch 层 !!js、安装期脚本、开机自启、凭据复制、出网域名与提示词注入面。Audit third-party DSH plugins before installing. Works with DSH, Claude Code, Codex, Cursor & any Agent Skills compatible agent.
- Stars
- 0
- Language
- PowerShell
- Created
- Sep 15, 2026
- Updated
- Sep 15, 2026
Introduction
plugin-audit
中文 · English
装插件之前,先看一眼它要碰什么。
一个给 DeepSeek Harness(DSH) 用的 Agent Skill:一次静态安全审计,把 eval、patch 层 !!js、安装期脚本、开机自启、凭据复制、出网域名、子进程调用、提示词注入面全部扫出来,按「硬否决 / 待确认能力 / 观察项」三层给出结论。
第三方插件是别人写的、与你同进程同权限运行的代码。它能不能跑,装之前几乎没人看得见;装之后又不一定回得去。这个技能把「装之前先看一眼」变成一条命令。
注意: 本项目为社区项目,与 DeepSeek 官方无隶属关系,亦未获官方背书。
为什么需要它
DSH 对「模型行为」有生产级防护(沙箱、权限、审批),但对「插件代码」没有安全设计。以下四条来自官方 Discussion #454 以及第三方插件安全审计报告:
| 事实 | 后果 |
|---|---|
| 插件与宿主同进程、同权限 | 插件能做的事 = DSH 能做的事 |
| 文件沙箱只挡「写」,不挡「读」 | 你的 ~/.dsh、.credentials.yaml、.ssh 都在可读范围 |
patch 层 !!js 表达式在加载期执行 | 光看 package.json 看不出任何异常,代码在装载时就跑了 |
| 恶意 bundle 安装即执行 | 而且事后 remove 清不掉已经落下的后门 |
也就是说:插件来源不明时,风险不在「功能不好用」,而在「你根本不知道它动了什么」。
它检查什么
脚本按三层归纳,全部是模式匹配 + 上下文过滤(跳过纯注释行,同一文件同一规则只算一条):
硬否决项(VETO)——单项即可否
| 项 | 命中内容 |
|---|---|
| 动态求值 | eval( / new Function / vm.runIn* |
| patch 注入 | !!js(加载期执行) |
| 安装期脚本 | postinstall / preinstall / prepare / prepublish |
| 开机自启 | 注册表 Run / schtasks / LaunchAgents / systemd unit |
| 凭据落盘 | 把 credential / .env / .ssh / id_rsa 复制到别处 |
待确认能力(RISK)——不是指控,是「它有权做什么」
| 项 | 命中内容 |
|---|---|
| 出网能力 | fetch / axios / WebSocket / net.connect |
| 遥测导出 | telemetry / otel / exporter |
| 远端地址 | 硬编码公网 URL(会另出一份域名清单) |
| 凭据读取 | process.env / .credentials.yaml / .npmrc / id_rsa |
| 命令执行 | child_process / spawn / execFile / taskkill |
| 启动路径 | 触碰 cordis.patch.yml / dsh.profile.bundles |
| 指令注入面 | 注册系统提示、agent/pre-step、向会话注入消息 |
| 不可信内容回灌 | 「读外部内容 → 拼进 prompt」的形状 |
| 文件写入 | writeFile / appendFile / rmSync / unlinkSync |
| 供应链 | git+ / github: / 运行时拉远端代码 |
| 官方包路径 | 引用或操作 node_modules/@deepseek-ai |
观察项(INFO)——知道即可
常驻轮询 / 心跳 / 看门狗(setInterval / watchdog);自更新与热加载(self-update / autoUpdate)。
输出怎么读
- VETO:逐条确认是「真实行为」还是「误报」——脚本已跳过纯注释行,但仍可能命中字符串常量或文档文本。
- RISK:重点看出网域名清单,分清已被标注的文档/命名空间类域名(
w3.org、github.com、json-schema.org等)与真实连接目标。 - INFO:常态行为,知道即可。
一句话记住:命中 ≠ 恶意,零命中 ≠ 无害。脚本给的是「该看哪里」,结论要落到读代码上。
安装
技能名 plugin-audit(本仓库名为 dsh-plugin-audit)。任选一种方式:
# 方式一:skills CLI(DSH 尚未被 CLI 收录,借 cline 的目录映射落到 ~/.agents/skills/)
npx skills add kiterunner1/dsh-plugin-audit -g -a cline -y
# 方式二:手动 clone —— 目标目录名要用技能名 plugin-audit
git clone https://github.com/kiterunner1/dsh-plugin-audit.git ~/.agents/skills/plugin-audit
各 agent 的技能目录:
| Agent | 项目级 | 用户级 |
|---|---|---|
| DeepSeek Harness | <project>/.dsh/skills/(rank 100)或 <project>/.agents/skills/(rank 200) | ~/.dsh/skills/(rank 400)或 ~/.agents/skills/(rank 500) |
| Claude Code | <project>/.claude/skills/ | ~/.claude/skills/ |
| Codex | <project>/.codex/skills/ | ~/.codex/skills/ |
| VS Code Copilot | <project>/.agents/skills/ | ~/.agents/skills/ |
| 其它兼容 agent | 按该 agent 的技能目录约定 | 同上 |
不需要重启:DSH 会监视这些目录,新技能在下一个模型步骤进入技能目录。验证办法——问 agent「帮我审一下这个插件安不安全」,技能应被触发;DSH 里也可以直接 skill(plugin-audit) 加载确认。
用法
脚本就在技能目录里,用技能自己的 base directory 拼路径调用即可:
# 审计一个目录
pwsh -File "<base>/scripts/audit-plugin.ps1" -Path <插件目录>
# 按包名审计:自动在 <DSH_HOME>/profiles/*/node_modules 与 npm 全局里找
pwsh -File "<base>/scripts/audit-plugin.ps1" -Path <package-name>
# 多个目标:逗号分隔(重复写 -Path 会报参数绑定错误)
pwsh -File "<base>/scripts/audit-plugin.ps1" -Path ./plugin-a,./plugin-b
# 机器可读
pwsh -File "<base>/scripts/audit-plugin.ps1" -Path <目录> -Json
按包名时不必写全 @scope/name——只给 name 也能找到 @scope/name。脚本只读:不改文件、不装任何东西。
输出示例
(格式示意;数值取自一次真实运行,包名、仓库与行号已匿名化)
═══ 插件安全审查:<plugin-name> ═══
目录 : ~/.dsh/profiles/web/node_modules/<plugin-name>
包/版本 : <plugin-name>@1.2.3 license=MIT
规模 : 源文件 25 依赖 1 开发依赖 3 .git=False
dsh 字段: bundle, client, compatibility
结论:未命中硬否决项 —— 请核对下方能力/域名清单后决定
硬否决项 0 条 · 需确认能力 6 类 · 观察项 0 类
── 能力清单(不是指控,是"它有权做什么")──
[出网能力] 2 个文件命中 — 发起网络请求(看下方域名清单:连了谁、传了什么)
lib/client.js:3 fetch( (x1)
[供应链] 1 个文件命中 — 非固定来源依赖 / 运行时拉远端代码
package.json:96 git+ (x1)
[凭据读取] 4 个文件命中 — 读取环境变量/凭据(与出网组合即为外传面)
lib/config.js:77 process.env (x1)
[启动路径] 1 个文件命中 — 触碰 DSH 启动组合(patch/bundles):写坏即起不来
package.json:21 cordis.patch.yml (x2)
[文件写入] 2 个文件命中 — 写/删文件(看写到哪:自己目录内 vs 全盘)
lib/store.js:130 writeFileSync( (x1)
脚本代替不了的人工必读
模式匹配只能缩小范围,下面四项必须人来读:
package.json的scripts(尤其postinstall/prepare)与dsh字段。cordis.patch.yml全文——特别是有没有!!js。- 入口文件里「读外部内容 → 拼进 prompt」的形状,那是提示词注入的主通道。
- 依赖来源:固定版本,还是
git+/github:/ 运行时拉远端代码。
审完之后:隔离试装
不要直接装进日常在用的 profile。用临时 profile 加独立端口:
dsh plugin --profile tmp-audit add <包名或 github:owner/repo#<commit>>
dsh --profile tmp-audit --dump-config # 核对组合能否正常解析
两条纪律:装插件时必须停掉正在运行的 DSH,否则 profiles/<name>/node_modules 会被删到一半失败,留下「当前能跑、重启必死」的 profile;依赖尽量 pin 到 commit(github:owner/repo#<sha>),别让它跟着默认分支漂。
平台支持
- 需要 PowerShell 7+(
pwsh),Windows / macOS / Linux 均可。 - 只依赖 PowerShell 标准 cmdlet,不需要 Node、Python 或任何第三方模块。
- 路径解析走
DSH_HOME/USERPROFILE/HOME,不假设你的用户名或安装位置。
FAQ
Q:它会不会漏? 会。这是静态模式匹配,只能看见「长得像危险行为」的代码。混淆、动态拼接、运行时下载都能绕过它。它的定位是降低盲目安装的概率,不是替代审计。
Q:命中 VETO 就一定是恶意吗?
不一定。比如一个插件在文档字符串里写了 !!js 三个字符也会命中。所以 VETO 是「停下来人工确认」,不是「自动判死」。
Q:为什么还需要人读 cordis.patch.yml?
因为 patch 层的 !!js 是加载期执行,它不在常规 JS 入口里,静态扫描容易漏,而且写坏的 patch 会让 DSH 直接起不来。
Q:能给非 DSH 的插件用吗?
能。它扫的是「代码会碰什么」,与宿主是不是 DSH 无关;只有少数规则(dsh 字段、cordis.patch.yml、@deepseek-ai 路径)是 DSH 专属,对其它生态不命中而已。
目录结构
dsh-plugin-audit/
├── SKILL.md # 技能入口:何时用、怎么跑、怎么读结果、试装纪律
├── README.md / README.en.md
├── LICENSE # MIT
├── .gitattributes
└── scripts/
└── audit-plugin.ps1 # 审计脚本(只读)
维护与贡献
- 新增规则要能说明「它防的是什么真实风险」,否则宁可不加——一个什么都报警的闸门等于没有。
- 遵守 Agent Skills 约束:
name为 kebab-case;description精炼(DSH 目录注入默认截到 500 字符);正文渐进式披露。 - 欢迎 PR:新规则、误报修正、更多 agent 的目录适配、英文版完善。
License
MIT——见 LICENSE。