← Back to home@kiterunner1

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

repo size last commit MIT license Agent Skills compliant

装插件之前,先看一眼它要碰什么。

一个给 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)

脚本代替不了的人工必读

模式匹配只能缩小范围,下面四项必须人来读:

  1. package.json 的 scripts(尤其 postinstall / prepare)与 dsh 字段。
  2. cordis.patch.yml 全文——特别是有没有 !!js。
  3. 入口文件里「读外部内容 → 拼进 prompt」的形状,那是提示词注入的主通道。
  4. 依赖来源:固定版本,还是 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。