工具管线上的运行时安全网关:拦截出站白名单之外的主机调用,在 canonical value(而非仅渲染内容)层面脱敏结果中的凭据,每个决策写入 JSONL 审计日志;默认仅监控不拦截。
安装
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:tancheng33/dsh-egress-guard
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
该插件的 README 只有英文版本。
English | 中文
A runtime security gate for DeepSeek Harness tool calls.
Existing security plugins in the ecosystem scan configuration files before an agent runs. This one sits in the tool-execution pipeline and acts on the calls themselves:
| Rule | Extension point | What it does |
|---|---|---|
| Egress allowlist | tools/pre-execute |
Denies (or asks about) a call that names a network destination outside your allowlist — curl to a paste site, git push to an unknown remote, a fetch to an exfiltration endpoint. |
| Secret redaction | tools/post-execute |
Rewrites credentials out of a tool result before the model, the durable session log, or a Code Mode program can read them. |
| Audit log | both waterfalls | Appends every decision — including the ones monitor mode only would have made — to a JSONL file. |
No fork, no patched loop: three listeners on documented extension points, disposed cleanly on unload.
Install
dsh plugin --profile <name> add dsh-egress-guard
The bundle ships mode: monitor, so installing it cannot break a working setup: every rule is evaluated and audited, nothing is blocked or rewritten. Read the audit log for a day, then turn on enforcement in your profile's cordis.patch.yml:
- id: egress-guard
config:
mode: enforce
egress:
enabled: true
allowHosts: ['*.github.com', '*.npmjs.org', 'api.deepseek.com']
denyHosts: []
allowLoopback: true
onViolation: deny
redact:
enabled: true
builtins: true
extraPatterns: []
placeholder: '[redacted:{name}]'
audit:
enabled: true
path: ''
logAllowed: false
A patch replaces a row's whole config, so restate every key you want to keep.
Configuration
| Key | Default | Meaning |
|---|---|---|
mode |
monitor |
off registers nothing. monitor evaluates and audits without acting. enforce denies and redacts. |
egress.allowHosts |
[] in schema, a starter list in the bundle |
Permitted hosts. *.example.com covers the apex and every subdomain. An empty list means denylist-only. |
egress.denyHosts |
[] |
Always denied. Beats allowHosts and allowLoopback. |
egress.allowLoopback |
true |
Exempts localhost, 127.0.0.0/8, ::1, *.localhost. |
egress.onViolation |
deny |
ask routes to ctx.approval instead — and degrades to deny when no approval service is mounted. |
redact.builtins |
true |
Private keys, vendor API keys, JWTs, bearer headers, KEY=value assignments. |
redact.extraPatterns |
[] |
Extra regex sources, compiled with the global flag. |
redact.placeholder |
[redacted:{name}] |
{name} is the pattern that matched. |
audit.path |
$DSH_HOME/egress-guard.jsonl |
JSONL, one decision per line. |
audit.logAllowed |
false |
Also record calls that named a host and passed — this is how you build an allowlist out of real traffic. |
Building an allowlist from real traffic
# 1. Install (monitor mode) and work normally for a while, with logAllowed: true.
# 2. See which hosts your agent actually reaches:
jq -r '.hosts[]?' ~/.dsh/egress-guard.jsonl | sort | uniq -c | sort -rn
# 3. Put the legitimate ones in allowHosts, then flip mode to enforce.
Design notes
Redaction happens at the canonical value, not the rendered content. The registry's contract is explicit that content replacement is not a confidentiality boundary — a Code Mode program receives the canonical value directly. So a successful result is redacted by replacing its value, and the content is re-rendered from the redacted value. Failed results carry no value (the registry rejects a value replacement on them), so their message is redacted as content.
The guard runs last in the post-execute waterfall. It delegates with next() first, then redacts whatever projection the composed decision actually carries, so a listener deeper in the waterfall cannot reinstate the original text. When another plugin replaced the content but the underlying value holds a secret, the guard replaces the value — losing that plugin's presentation, but not leaking to programmatic consumers. That precedence is deliberate.
Denials tell the model not to route around them. A bare "denied" invites a retry with a different tool; the reason string names the hosts and says to ask the user instead.
Limitations — read this before trusting it
This is a guard rail, not a containment boundary. It raises the cost of an accident or a careless prompt injection; it does not stop a determined adversary running code on your machine.
- Detection is textual. Destinations are found by scanning argument strings for URLs and
user@hostremotes. A command that assembles its destination at runtime (curl "$ENDPOINT", base64, string concatenation, an IP in decimal form) is invisible to the gate. Real containment is the sandbox seam's job (dsh-bash-sandbox, network namespaces, a proxy), not a string matcher's. - A tool that opens its own socket bypasses the gate entirely unless the destination appears in its arguments.
- Redaction is pattern-based, so it misses credential shapes it does not know, and it can rewrite text that merely looks like a secret. Add
extraPatternsfor your own formats; check the audit log for false positives before enforcing. - Binary content is not scanned — image blocks and other non-text blocks pass through untouched.
- The audit log is local and unsigned. Anything that can write to your filesystem can edit it.
Compatibility
Built against the @deepseek-ai/dsh-tools 0.1.5 / 0.1.6 pipeline contract; dsh.compatibility.dshReleases in package.json carries the per-release declaration.
Verified on 2026-09-22, each release line pinned across the whole @deepseek-ai/dsh-* family:
| DSH release | typecheck | build | tests |
|---|---|---|---|
0.1.5-rc.2 (npm latest) |
pass | pass | 61/61 |
0.1.6-alpha.1 |
pass | pass | 61/61 |
0.1.6-alpha.2 (npm alpha) |
pass | pass | 61/61 |
On 0.1.5-rc.2 the packed tarball was also installed into a disposable profile (DSH_HOME pointed at a throwaway directory, --from-default-profile headless): the bundle composes into the profile tree as the egress-guard row, the profile boots with it loaded — stopping only at the provider credential gate — and dsh plugin remove takes both the dependency and the row back out.
0.2.0 drops the 0.1.0-rc line. Upstream renamed CallId to ToolCallId and moved JsonValue out of dsh-session, so a build against 0.1.0-rc.6 fails. Stay on 0.1.0 of this plugin if you are still on that harness line.
Note that npm's latest tag for the @deepseek-ai/* packages now points at 0.1.5-rc.2, with the 0.1.6 prereleases on the alpha tag. If you install harness packages by hand, ask for the version explicitly.
The harness is in developer preview and states that compatibility-breaking changes will happen. If a pipeline contract shifts, this plugin's tests are designed to fail loudly — they execute real calls through a real registry rather than mocking the waterfalls.
Development
npm install
npm test # 61 tests: pure unit tests + end-to-end through a real ToolRuntime
npm run typecheck
npm run build
Every release in dsh.compatibility.dshReleases is exercised by CI. To reproduce one locally, pin the whole harness family and run the suite against it (package.json and the lockfile are restored afterwards):
node scripts/pin-dsh.mjs 0.1.6-alpha.2
npm run typecheck && npm test && npm run build
To try it against a live harness without publishing:
dsh plugin --profile <name> add /path/to/dsh-egress-guard
dsh --profile <name> --dump-config # shows the "# == dsh-egress-guard" layer
License
链接
同类插件
kenryu42/cc-safety-net★ 2009
执行前守卫,在工具调用运行前拦截破坏性 Git 与文件系统命令,以及对 SSH 密钥、.env 等机密文件的访问。
ADWMC/helm-d#helmd★ 1235
DeepSeek Harness 的安全分析插件:33 个工具覆盖六大安全域、证据/报告与工具集,并提供案件生命周期、路由和工具账本;按会话绑定的案件工作区支持证据链、E 编号校验与可复现结论(repro_cmd);内置 362 篇按需参考、三档可热切换人设,以及带案件状态恢复的破甲 / Case / 拦截 / 关于四页工作台。
toby-bridges/api-relay-audit★ 911
从 DeepSeek Harness 对 AI API 中转站和 LLM 代理运行本地安全审计,生成 Markdown 报告,覆盖提示词注入、模型替换信号、工具调用改写、错误泄漏、流完整性和按 profile 启用的 Web3 风险。
SeaOf0/dsh-redteam-model★ 874
面向授权安全研究的 DSH 合集:九个工作模式(redteam 总控、渗透测试、代码审计、二进制分析、攻防评估、免杀对抗、应急溯源、云安全攻防、CTF 解题)与十五个运行时插件,设置页管理台支持一键部署、安装、更新与卸载。
howmp/dsh-pentest★ 619
面向 DeepSeek Harness 的授权渗透模式:以探索链路记录目标、线索、资产与漏洞,并在 Web 中可视化展示。
PerryLink/dsh-auto-review★ 248
审批链上的第二模型自动审查:只读审查子代理返回带理由的 allow/deny 结构化裁决,默认 fail-closed。
社区评论
评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。