toby-bridges/api-relay-audit
toby-bridges/api-relay-audit从 DeepSeek Harness 对 AI API 中转站和 LLM 代理运行本地安全审计,生成 Markdown 报告,覆盖提示词注入、模型替换信号、工具调用改写、错误泄漏、流完整性和按 profile 启用的 Web3 风险。
白名单目录写入免审批——write/edit 文件工具直通白名单栅栏,命中白名单的 bash 沙箱升权自动放行,设置页可视化管理目录与开关。
DSH plugin: approval-free writes into whitelisted directories. Let the write/edit file tools modify configured whitelist directories (e.g. your Obsidian vault) directly — no more "sandbox denial → escalation retry → manual approval" — plus a Settings → Plugins → Directory Allowlist GUI and automatic approval for bash escalations that touch whitelisted paths. Behavior everywhere else stays exactly as before.
| Layer | Mechanism | Covers |
|---|---|---|
| write/edit tools | Wraps the ctx.fs.checkedTarget fence; whitelisted paths pass early | Approval-free vault reads/writes |
| bash commands | tools/pre-execute indexes the command text; approval/request auto-answers allowed-once when the command or escalation reason hits a whitelisted path (recursive check) | Approval-free bash writes (command text first; misses fall back to manual approval) |
| Settings GUI | settings.plugins.tab section + server-side HTTP management routes | Add/remove directories, toggle bash auto-approve visually |
Configuration is hot-reloaded: GUI edits apply instantly; manual edits to the config file are picked up within 3 seconds. No DSH restart needed.
Every write/edit tool call passes through the ctx.fs.checkedTarget() fence mounted by dsh-fs-sandbox (outside the workspace → FS_SANDBOX_DENIED → model retries with escalation → approval prompt). This plugin wraps that fence:
read-only mode / resolution failure) → delegate to the original fence untouched.File semantics — atomic writes, version guards, read-before-write checks, diff events — live in the parent dsh-fs-local provider below the fence and are not touched. Whitelist matching uses the same realpath (deepest existing ancestor) semantics as the fence, so symlink redirection cannot escape the allowlist.
bash runs under the Seatbelt process sandbox, whose profile cannot be extended from a plugin. Instead two listeners cooperate: tools/pre-execute records each bash call's command text by callId, and the approval/request answerer looks it up and matches the command text plus the escalation reason against the allowlist — path-like tokens are extracted, ~ is expanded to home, then recursively checked under whitelisted roots (a parent entry covers all its children). The command text almost always contains the target path, so approval no longer depends on the model writing it in the justification. Misses always fall back to the human prompt (fail-safe). Toggle it off any time in the settings page.
dsh plugin --profile web add /path/to/dsh-fs-allowlist
or from GitHub after release:
dsh plugin --profile web add "github:wzn16/dsh-fs-allowlist#main"
Installs into $DSH_HOME/profiles/web; restart DSH Desktop to take effect (refreshing the browser is not enough). The profile links the source directory, so editing the source only needs a restart — no reinstall.
$DSH_HOME/fs-allowlist.json (default: ~/Library/Application Support/dsh-desktop/harness/fs-allowlist.json on macOS; the resolver also understands $DSH_HOME, Windows %APPDATA%, Linux XDG paths, and the open-source ~/.dsh layout):
{
"extraWritableRoots": [
"/Users/you/ObsidianVault"
],
"bashAutoApprove": true
}
bashAutoApprove defaults to true when absent.| Scenario | Behavior |
|---|---|
| write/edit inside the workspace | approval-free (native, unchanged) |
| write/edit inside a whitelisted root | approval-free |
| write/edit anywhere else | deny → escalate → approval (unchanged) |
| read-only mode writing a whitelisted root | still denied (stricter knob wins) |
| bash touching a whitelisted root (command or reason matches) | auto-approved, no prompt |
| any other bash escalation (no match) | normal approval prompt |
checkedTarget is an internal seam of the shipped bundle: if a DSH upgrade refactors it, the plugin degrades loudly to "warn + transparent" (equivalent to today's behavior) without breaking sessions; adapt per release.dsh plugin --profile web remove dsh-fs-allowlist (or empty fs-allowlist.json) + restart DSH.
MIT