dsh-shield
The security firewall for DeepSeek Harness.
Scan before install. Guard before execution. Audit after action.
> Don't trust your agent's tools. Verify them.
Install
Requires Node.js 20+ and pnpm.
1. CLI (preflight scanner)
git clone https://github.com/245678000000/dsh-shield.git
cd dsh-shield
pnpm install
pnpm build
pnpm link --globaldsh-shield --help
dsh-shield doctor
dsh-shield scan ./fixtures/plugins/processOr run from the checkout without a global link:
node packages/cli/dist/bin.js scan ./some-plugin2. Runtime plugin (DeepSeek Harness)
Prefer a local path. Do not allowBuilds an unreviewed git prepare:
dsh plugin --profile web add /path/to/dsh-shieldRestart dsh web. Default profile is balanced. Optional policy file: ~/.dsh-shield/policy.yaml.
Do not start with dsh plugin add github:245678000000/dsh-shield unless you have scanned and pinned a commit.
Two layers — this is not a normal plugin
Install-time malice cannot be stopped by a plugin that only loads after install. dsh-shield is therefore two products that share one security model:
Before installation
→ Preflight Scanner
During execution
→ Runtime Shield| Layer | What it is | When it runs |
|---|---|---|
Preflight CLI dsh-shield scan | Download / extract / parse / inspect. Never executes the target. | Before dsh plugin add |
| Runtime plugin | Cordis plugin on official tools/pre-execute + ctx.tools.guard() | Every tool / MCP call |
Why
DeepSeek Harness (dsh) is an open agent runtime: plugins, MCP servers, and tools all run with the authority of the host process. Users install github:someone/plugin through pnpm. Lifecycle scripts can run before any Harness hook exists. MCP tools named mcp__<server>__<tool> can send local data off-box.
dsh-shield gives you SCAN / CLASSIFY / ALLOW / ASK / DENY / AUDIT at those boundaries.
It is risk detection, policy enforcement, trust metadata, human approval, and auditability. It is not perfect security.
Threat model
See [docs/threat-model.md](docs/threat-model.md).
We consider: malicious plugins, compromised dependencies, malicious MCP servers, prompt-injection content, data exfiltration, dangerous tool calls, tool confusion (read-only vs write), supply-chain drift, and dynamic configuration.
We do not claim: 100% prompt-injection prevention, proofs of safety, a JS sandbox, detection of every obfuscated payload, or a replacement for OS sandboxing.
Architecture
DSH SHIELD
│
┌─────────────┴─────────────┐
↓ ↓
PREFLIGHT SECURITY RUNTIME SECURITY
│ │
├─ Package Scanner ├─ Tool Gate
├─ Source Scanner ├─ MCP Gate
├─ Dependency Scanner ├─ Egress Guard
├─ Script Scanner ├─ Approval
├─ Permission Inferencer ├─ Sensitive Data
├─ Risk Engine ├─ Injection Signals
└─ Trust Manifest └─ Audit LogPackages:
@dsh-shield/core— findings, capabilities, risk, policy, secrets@dsh-shield/scanner— non-executing preflight@dsh-shield/cli—dsh-shieldbinary@dsh-shield/runtime— Harness plugin@dsh-shield/ui— formatters (CLI now; Web later)
Preflight scanner
pnpm add -g dsh-shield # or: pnpm exec dsh-shield from this repo
dsh-shield scan ./some-plugin
dsh-shield scan github:someone/agent-plugin#<sha>
dsh-shield scan npm:some-package
dsh-shield inspect ./some-plugin
dsh-shield policy check ./some-plugin
dsh-shield manifest ./some-plugin
dsh-shield doctor
dsh-shield diff old.manifest.json new.manifest.jsonExample:
DSH SHIELD
────────────────────────────
Target:
github:someone/agent-plugin
Overall risk: HIGH
⚠ prepare install script
⚠ child process execution
⚠ network access
⚠ environment access
⚠ unpinned Git source
Capabilities:
fs.read fs.write process.spawn network.connect env.read
Recommendation:
REVIEW BEFORE INSTALLINGScanning never runs npm install, never require()s the target, and never executes lifecycle scripts. Remote specs are download → extract (zip-slip safe) → parse → inspect.
Runtime guard
Install as a Harness bundle after you have scanned this package itself (yes, we have a prepare story — pin a commit / use a tarball; see below).
dsh plugin --profile web add ./dsh-shield
# or, once published:
dsh plugin --profile web add dsh-shieldThe plugin uses current official APIs (Harness 0.1.0-rc.5, commit 47f94385):
tools/pre-execute→{ kind: 'allow' | 'ask' | 'deny' }ctx.tools.guard()→ monotonic DENY- official ASK →
ctx.approval.request(); missing approval denies - MCP names:
mcp__<serverName>__<rawName>
It does not fork the agent loop.
MCP security
New MCP servers default to unknown, not trusted.
| unknown MCP | reviewed (e.g. github) | |
|---|---|---|
| read + non-sensitive | ASK (balanced) | ALLOW |
| external write | ASK | ASK |
| secret / credential egress | DENY | DENY |
Data egress
Before an external MCP / HTTP tool runs, arguments are classified:
public | internal | personal | confidential | credential | secret
Secrets are redacted in logs and approval reasons (sk-abc...xyz, never the raw value).
DATA EGRESS WARNING
Destination: crm-cloud
Detected: CONFIDENTIAL DOCUMENT, PERSONAL DATA, POSSIBLE SECRET
Action: DENYPrompt injection
Detection, not magical prevention.
Untrusted web / MCP / README content is scanned for instruction-like signals and tagged UNTRUSTED_*. A later sensitive read or external write in the same session is raised to ASK/DENY (SHIELD-INJECT-002). The original text is not deleted.
Policy
YAML / JSON. Built-in profiles: permissive, balanced (default), strict, enterprise. See [examples/policy/balanced.yaml](examples/policy/balanced.yaml) and [docs/security-model.md](docs/security-model.md).
Invalid config fails closed on high-risk decisions.
Trust manifest
dsh-shield manifest <target> writes dsh-shield.manifest.json:
schema version, package, source + commit, risk, capabilities, install scripts, findings, completeness, scanner version.
Trust store entries are (source, commit). A new commit invalidates trust.
Harness integration
Researched against official source. Details: [docs/harness-integration.md](docs/harness-integration.md).
Examples
Synthetic fixtures live in fixtures/. They are not malware.
pnpm install
pnpm test
pnpm dsh-shield scan fixtures/plugins/process
pnpm exec vitest run tests/runtime/demos.spec.ts| Demo | Result |
|---|---|
read_file of workspace source | ALLOW |
mcp__github__get_issue (reviewed) | ALLOW |
mcp__github__create_issue | ASK |
unknown MCP + TEST_API_KEY=shield_test_123456 | DENY |
injected README → upload_debug_info | DENY |
Security model
[docs/security-model.md](docs/security-model.md) · [rules/catalog.md](rules/catalog.md)
Risk scores are deterministic. An LLM cannot decide ALLOW/DENY.
Privacy
Local first. No default cloud analysis. Audit logs keep rule IDs, decision, destination, data class, and a redacted excerpt. They do not keep raw secrets or full confidential documents.
Limitations
[docs/limitations.md](docs/limitations.md)
What can dsh-shield NOT guarantee? Safety proofs, complete prompt-injection prevention, a JS sandbox, detection of every obfuscated loader, MCP honesty, or protection after you have already allowed a package's install scripts to run.
Testing
pnpm lint
pnpm typecheck
pnpm test
pnpm buildCI runs those four. Fixtures are synthetic. CI never executes unknown third-party packages.
Roadmap
- v0.1 — preflight scanner, runtime policy, MCP trust, egress
guard, audit (this release)
- v0.2 — richer manifest diff UX, registry reputation adapters,
deeper origin tracking, optional Web UI
- v0.3 — signed trust manifests, plugin transparency, CI action
- v0.4 — organization policies, central distribution
Install notes (supply chain)
dsh plugin add github:245678000000/dsh-shield fetches source. Official Harness docs say a git install may run prepare after you allowBuilds. That is exactly the threat this project exists to warn about.
Prefer:
- a published npm tarball with prebuilt
dist/, or dsh-shield scan github:245678000000/dsh-shield#<sha>then pin that sha
Contributing
Issues and PRs welcome. Do not add an LLM as the security boundary. Do not execute scan targets. Do not invent Harness APIs — re-read docs/harness-integration.md and the official tree.
See [SECURITY.md](SECURITY.md) for vulnerability reports (GitHub Security Advisories).