A Plugin for DeepSeek Harness (dsh)

The trust layer for
DeepSeek Harness plugins.

dsh-plugin-vet is the trust layer for DeepSeek Harness: deterministic static scan (R1–R20), an alarm-only runtime guard with honeypot lures, an agent audit-protocol skill, and a live GUI shield.

A monitoring alarm, not an enforcer. vet never acts on your behalf — it only does check → alarm → advise. The final call is always yours on your own DSH.
dsh plugin --profile <profile> add @jieai/dsh-plugin-vet
● live guard · alarm-only
T1 sentinel T2 hooks HP honeypot
1102tests · 1102 passed
88.7%line coverage
20static rules R1–R20
34/8mutant gate · killed / clean
12platform skips (win / mac)
What it does

One pipeline, from download to runtime.

vet occupies the whole trust chain — download → scan → audit → score → decide → runtime watch — and stops there: it reports, it advises, it never enforces.

🔬

Deterministic static scan

R1–R20 rules over an AST (engine v20), verdicts produced only by the static layer — never spoofable by prompt injection. The scanner runs as an isolated subprocess: AST read-only, never eval'd.

verdict · critical / suspicious / clean
📡

Runtime guard — alarm only

T1 sentinel watches host resources (Linux: /proc; macOS: ps/lsof + fs watch — memory, forks, fds); T2 hooks wrap fs/child_process and attribute dangerous operations to the plugin that did them. Watches, never kills.

alarm-only by default
🪤

Honeypot lures

Fake credentials planted in an unobtrusive location (no honeypot keywords — anti-honeypot). Anyone rifling through key files gets caught red-handed with high confidence.

opt-in · honeypot.enabled
🧾

Audit-protocol skill

The agent reviews a plugin in preset steps and writes a health record to disk; `requireAudit` turns "unaudited" into "unusable". Official packages anchor to a content hash baseline (contentBaseline) — a changed tarball is surfaced, never silently trusted. vet ships criteria, not conclusions.

vet-audit-protocol
🛡️

Live GUI shield

A green/yellow/red status light in the DSH web header with live metrics, per-alarm advice, one-click dismiss, and a runtime-guard toggle. Click to inspect, never to act.

status.json · polled
🧯

Supply-chain OSV check

Exact-version known-vulnerability queries against Google OSV for the plugin and its direct dependencies. Network trouble degrades silently — never a false block.

osvCheck · exact versions
🧘

Alarm-fatigue control (0.3.3)

Coverage-class boundary alerts are deduplicated persistently by (kind, pkg, version, capability diff) — the same version never re-alarms, an upgrade that changes capabilities does. Official-anchor C2 notices downgrade to info and fold across packages; the store fails open (repeat a notice, never go blind).

known-boundaries · fail-open
🎯

Kill-rate gate

A QA contract, not a claim: 34 malicious mutants must all be killed and 8 benign controls must stay clean — enforced by `--gate` on every release. Escape shapes are added as corpus, never deleted.

34 killed · 8 clean · R1–R20
📦

Published-artifact self-pin

Every release pins a hash of its shipped artifacts (`vet-self-pins.json`). Change the code without re-pinning and the self-scan gate fails — byte-swapped or tampered installs are caught on scan.

gen:self-pin · pinned-match
Architecture

Two worlds, physically separated.

The scanner runs in its own process — even if the host is compromised by escaped plugin code, scan results still come from a clean, read-only process.

🖥️ DSH host process in-process

tools/execute guardScans cordis_define / cordis_run / run_code / workflow before execution.
internal/plugin guardAuto-scans newly installed third-party packages + requireAudit gate + content hash baseline for official packages.
T1 sentinelSidecar subprocess samples host resources (/proc on Linux, ps/lsof + fs watch on macOS) → alarm JSON lines back.
T2 hooksWraps fs / child_process; stack attribution to the plugin package; C2 ESM blind spot explicitly flagged (esm-guard-coverage).
🪤 HoneypotFake key lures; touching them = high-confidence key hunt.
🧘 known-boundaries (0.3.3)Persistent dedup store (kind, pkg, version, capability diff) — fail-open, auto-revoke on change.
webServer /vet/*GET status.json (shield polling) · POST runtime-guard toggle.
Dual-OS CI gate: ubuntu coverage ratchet · macOS real ps/lsof integration
spawn · request-response · exits after each scan

🧠 scanner-bin isolated subprocess

Read stdin JSONcode / files / rules / targetKind / runtime.
AST parseTypeScript compiler API — read-only, never eval'd.
Run rules R1–R20static engine v20 → score → staticScore → verdict → single-line stdout JSON.
⚡ Cachecontent hash + engine version + rule set + targetKind/runtime.
🧯 OSVExact-version known-vuln query; silent network downgrade.

Detail in docs/ARCHITECTURE.md · trust boundaries below.

Dashboard

Measured, not marketed.

Real numbers from the test suite and coverage run — a security layer should be able to show its receipts.

Coverage vs. enforced thresholds

vitest v8 · v8 provider · thresholds lines/functions/statements ≥ 85%, branches ≥ 80% (ratchet, round-18)

1102 tests by suite

1102 passed · 12 platform-specific skips (win / mac /proc)

Adversarial matrix verdicts

34 mutants + 8 benign controls across R1–R20 · kill-rate gate enforced

Static rule severity map

Default severity per rule (R1–R20)
Trust boundaries

Design constraints that keep it honest.

01

The verdict comes only from the deterministic static layer — regex/AST judgments, not spoofable by prompt injection.

02

The static layer is physically isolated from plugin code — a separate process, AST read-only, never eval'd.

03

No single merged score — the verdict is never blended with subjective review into one number.

04

Fail-open by default — `mode: report`; deny interception is an explicit deployer opt-in.

05

Alarm-only runtime guard — watches, never kills. Interception exists only in the opt-in watch mode, for confirmed destructive operations.

06

Not a security boundary — a "speed bump + forensics layer", aligned with DSH's official stance.

07

Deduplication never goes silent — the known-boundaries store fails open: a damaged or unwritable store means the notice repeats, never that it disappears.

08

Differential trust for official anchors — noise drops inside the content-trust anchor (info, folded, counted out of `alarmCount`); the anchor itself is content-hash-verified, and everything outside it is alarmed as usual.

Known limitations

What we openly admit it can't catch.

A trust layer that hides its blind spots isn't a trust layer. All of these are empirically verified and documented.

01Static scan is not a security boundary: obfuscated/encoded/dynamically generated code can bypass AST rules.
02Indirect references (alias functions, globalThis.process, indirect eval) yield only info or zero findings.
03Runtime-constructed payloads (base64 strings, hex assembly, self-modifying code) can slip past.
04Non-source files (.jsx/.tsx/.vue/binaries/wasm/shell) are outside the scan surface.
05T1/T2 can't catch worker threads' separate realms, native plugins, process.binding, or slow low-traffic exfiltration.
06/vet/status.json has no auth — keep dsh web on loopback if you care about LAN read access.
07T2's stack attribution is best-effort; inside the official content-trust anchor, C2 coverage notices are info-severity observations (0.3.3) — escalation still applies for anything outside the anchor.
08The known-boundaries dedup store is per-machine: a fresh machine re-alarms once until the store is built; a damaged store repeats notices (the fail-open price).

Vet it. Then decide.

Install into any profile you want guarded. Reports by default, blocks only when you say so.

dsh plugin --profile <profile> add @jieai/dsh-plugin-vet