Skip to content

Latest commit

 

History

12 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

dsh-plugin-audit

一个可复用的 DSH skill(同时附带可独立运行的初筛脚本),用于在安装任何第三方 DeepSeek Harness 插件 / agent preset 之前,审查它的源码,帮你判断这件事安不安全。

这是仓库的入口说明。skill 本体的触发与执行规则见 SKILL.md;确定性初筛脚本见 scripts/scan.mjs;审计报告模板见 assets/report-template.md


为什么安装这个 skill

因为"装第三方插件"这件事,本质是授予它宿主机权限,而这件事没有自动防线替你兜底,只能靠你自己在装之前读一遍源码。这个 skill 把"读一遍源码"变成可复用、有结论的流程:

  1. 它替你记住前提:装第三方 host 插件 = 授予宿主任意代码执行权,让你不会因为 star 多、进了精选列表、别人说好用就跳过审查。
  2. 它让审查有抓手:先用脚本把危险信号定位出来,再有针对性地读、判断、给结论,而不是面对一个仓库无从下手。
  3. 它逼出带证据的结论:按固定模板输出,结论必须有文件 + 行号 + 语义判断,避免一句笼统的"应该没事"。
  4. 它诚实地划定边界:报告会写明"这只覆盖你给的这份源码",并提醒你锁版本——这是它区别于"自动安全扫描器"的地方,后者常给人虚假的安全感。

怎么安装和使用

安装

把整个 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_processfs 读凭据、net/http 外发、vm/module 等,因本来就在宿主进程里,无需绕过任何东西 scan.mjs模块能力抓(require("node:child_process")from "fs"import("vm") 都覆盖);AI 读上下文判断用途是否正当
③ 生命周期脚本投毒 package.jsonpostinstall/preinstall/preparepnpm install 时执行恶意代码 scan.mjs 匹配这些脚本字段;AI 读脚本内容确认
curl … | sh 远程执行 安装脚本从远端拉取并执行 shell,安装即中招 scan.mjs 匹配 curl|wget … | sh/bashevalbash -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.jsonmain/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

About

No description or website provided.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Contributors

Languages