dsh-egress-guard
Local, zero-network, deterministic secret preflight for DeepSeek Harness model requests.
dsh-egress-guard inspects the fully assembled request at the official llm/stream boundary. It first validates and freezes the exact plain-data request graph that downstream code will consume. If it finds a likely credential, it stops before calling the downstream model adapter. Matches never appear in the error, finding report, or plugin log.
The default policy is fail-closed:
- known secret patterns block the request;
- images and unknown content blocks block because this version cannot inspect their bytes safely;
- requests larger than the configured scan limit block;
- cyclic, proxy/accessor-backed, non-plain, sparse, oversized, non-enumerable, unknown-field, or otherwise unfreezable request graphs block even in audit mode;
- invalid configuration prevents the plugin from loading.
It does not rewrite request values and never sends request content to another service.
Install
From npm after the package is published:
npx --yes @deepseek-ai/dsh@0.1.0-rc.6 plugin --profile web add dsh-egress-guard
npx --yes @deepseek-ai/dsh@0.1.0-rc.6 --profile web --dump-config
From the public GitHub repository now:
npx --yes @deepseek-ai/dsh@0.1.0-rc.6 plugin --profile web add git+https://github.com/LKRCharon/dsh-egress-guard.git
npx --yes @deepseek-ai/dsh@0.1.0-rc.6 --profile web --dump-config
From a local checkout, use a file: specifier so pnpm installs a package copy instead of a symlink:
npx --yes @deepseek-ai/dsh@0.1.0-rc.6 plugin --profile web add file:/absolute/path/to/dsh-egress-guard
npx --yes @deepseek-ai/dsh@0.1.0-rc.6 --profile web --dump-config
For a release-equivalent local smoke test, run npm pack in the checkout and add the resulting .tgz by absolute path. Do not add a bare checkout path: rc.6 treats it as a symlink, which can bypass the profile's host-module fallback at real startup.
The preview CLI delegates plugin installation to pnpm, so ensure it is on PATH first. With Corepack, run corepack enable pnpm; alternatively install pnpm 11 directly. A global dsh install may replace the pinned npx prefix above. The dump should contain an egress-guard row before you start the profile.
DSH rc.6 profiles disable automatic peer installation. The add command can therefore warn about the @deepseek-ai/cordis and @deepseek-ai/dsh-llm peers even though the host supplies them at runtime. They intentionally remain peer dependencies so the plugin shares the host runtime and LlmError identity.
Default coverage
Built-in rules cover:
- PEM private keys;
- GitHub, AWS, Google, Slack, Stripe, npm, PyPI, Hugging Face, GitLab, and common
sk-*provider keys; - bearer and basic-auth credentials;
- credentialed PostgreSQL, MySQL, MongoDB, and Redis URLs;
- high-confidence
password=,api_key=,access_token=, and related assignments.
Common placeholders such as process.env.API_KEY, changeme, and your_api_key are ignored. Pattern matching is intentionally conservative; it is a safety layer, not a complete secret scanner.
Configure
Later DSH patch layers override a row by id. Add this to the profile's cordis.patch.yml and restate the row name:
- id: egress-guard
name: dsh-egress-guard
config:
mode: block
scanToolSchemas: true
blockUnscannable: true
maxScanBytes: 4194304
maxFindings: 64
skipProviders: []
skipPurposes: []
customRules: []
Available settings:
| Setting | Default | Meaning |
|---|---|---|
mode |
block |
block stops dispatch; audit logs redacted metadata and continues. |
scanToolSchemas |
true |
Scan tool descriptions and JSON schemas sent to the model. |
blockUnscannable |
true |
Block images, malformed model fields, and unknown future content types. Unsafe request graph structures always block. |
maxScanBytes |
4194304 |
Maximum UTF-8 request text scanned; exceeding it blocks. Range: 1 KiB–16 MiB. |
maxFindings |
64 |
Maximum distinct rule/location records retained. Counts still fail closed. |
skipProviders |
[] |
Provider routes that bypass the guard. |
skipPurposes |
[] |
Any of conversation, compaction, or session-title to bypass explicitly. |
customRules |
[] |
Up to 32 deterministic literal-prefix + fixed-alphabet suffix rules. |
Custom rule example:
customRules:
- id: acme-production-key
prefix: 'ACME-PROD-'
alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
length: 24
Custom rules do not execute regular expressions. The matcher finds a literal prefix, then requires exactly length characters from alphabet and a suffix boundary. Prefixes must be 4–64 printable ASCII characters and end in a delimiter outside the alphabet; alphabets contain 2–128 unique printable ASCII characters; suffix length is 1–256. This deliberately narrow format keeps custom scanning deterministic and avoids regular-expression backtracking.
What is scanned
- the system prompt;
- provider/model routing ids, reasoning effort, and session id metadata;
- each message's provider-facing text and reasoning channels;
- message source/provenance fields, including adapter replay metadata;
- raw JSON tool-call arguments;
- nested tool-result content, including text reconstructed across nested result layers;
- tool descriptions and parameter schemas;
- stop sequences;
- ordinary conversation, compaction, and session-title requests.
Text is joined only inside the same message and channel, matching the provider serializer. It is never joined across messages.
Safety boundary
This plugin prevents a matching request from reaching the downstream DSH model adapter. It is not a machine-wide network firewall.
Important limits:
- Text already entered into DSH may remain in the local session log even when outbound dispatch is blocked.
- Binary image contents are not OCR-scanned; they block by default.
- The guard freezes the same request object graph before scanning so a direct caller cannot mutate it during asynchronous adapter resolution; the live
AbortSignalremains unfrozen. - Encoded, fragmented, novel, or low-entropy secrets may evade regular-expression detection.
- A malicious plugin that exfiltrates data outside the normal downstream adapter path is outside this plugin's boundary.
- Same-process code that mutates shared JavaScript prototypes or other globals after preflight is also outside the boundary; the guard freezes the request's own plain-data graph, not the whole runtime.
auditmode records only rule ids, structural locations, counts, a one-way provider fingerprint, and request purpose, but it does not prevent egress.
Development
Requires Node.js 22.19.x or 24 and newer, plus DeepSeek Harness 0.1.0-rc.6 or a compatible 0.1.x preview.
npm install
npm run check
npm run pack:check
The package ships plain ESM and leaves @deepseek-ai/dsh-llm external so the host's LlmError identity remains intact.
中文说明
这是一个纯本地的 DSH 模型请求出站检查插件。它在 llm/stream 边界扫描完整请求;发现疑似密钥时不调用下游模型适配器,并返回固定的脱敏错误。默认不联网、不改写请求、扫描不了的图片或未知内容直接阻断。注意:它只阻止模型请求外发,不会自动清理已经写入本地 session 日志的原文。
License
MIT
No comments yet. Be the first to write one.