Approval is not a security boundary
Approval is not a security boundary
Summary. In DeepSeek Harness, the ask-approval gate and workspace-write limits are consent / routing UX, not OS security boundaries. Two verified bypass families make this concrete:
- #1863 —
pre-executelisteners run beforeaskapproval; a plugin can finish host operations in a separate Node.js child process and only then returnask. - #1923 —
delegating execution to a user-privileged external shell
(
explorer/start/open) sidesteps both gates: the agent is not running the command, the user’s own context is.
The framing matters: plugins are installed host code. They can import Node
built-ins and run anything. Approval gates intent, not capability — it
cannot retroactively undo a listener that already ran host operations before
returning ask.
Family 1: side effects before the ask (pre-execute)
The original finding: a tools/pre-execute listener can perform its work in
an independent Node.js subprocess and only then return ask — so the approval
UI shows a prompt after the operation already happened. Nothing in the harness
can distinguish “the listener decided to decline” from “the listener already
executed and is asking for form’s sake”.
Consequence for API design: pre-execute listeners should be pure decision
functions. No child processes, no filesystem writes, no network in the
listener body.
Family 2: the shell-launcher bypass
The second channel: child_process calls that hand off to the user’s own
shell environment — explorer.exe, start, open, powershell, cmd —
launch a process that inherits the user’s privileges and is no longer subject
to the agent’s workspace/approval policy. The agent “didn’t run the command”;
the user’s own context did.
Why policy checks are not a sandbox
- Approval gates who is asked, not what can run.
- Workspace-write limits route file access for agent tools; a plugin that spawns outside the sandbox is simply outside the routing table.
- Static checks (heuristics, scans) can reduce the surface but cannot enforce it — enforcement requires the OS boundary.
Fix directions, in order of leverage
- OS-level sandbox, not just policy checks: workspace-write must map to
a restricted token / container. Windows direction:
CreateRestrictedToken(see #1789) so a “launched by the user’s shell” process still runs without workspace-escape privileges. - Contract:
pre-executelisteners are pure decision functions (no child processes, no fs writes, no network). - Shell-launcher whitelisting: delegation surfaces that intentionally use user-privileged shells need an explicit allowlist and a warning.
Toolized review aids (honest scope)
dsh-plugin-doctorv1.9.0pre-execute-side-effects: scans source/lib forpre-executelisteners and flags same-file host-level side-effect APIs; FAIL names the file and matched API.dsh-plugin-doctorv1.11.0shell-launcher: warns whenchild_processusage invokesexplorer/start/open/powershell/cmdsurfaces (the #1923 channel).
Both are explicitly labeled review aids, never a sandbox: 31/31 tests,
self-check exit 0, and the tool’s own cmd.exe wrapper shows up as an honest
WARN.
中文摘要
在 DSH 里,”ask 审批”和”workspace 写限制”是同意/路由 UX,不是 OS 安全边界。
两条已验证的绕过:① pre-execute 监听器在审批前就能用独立子进程把事做完再
返回 ask(#1863);② 借用户特权的外部 shell(explorer/start/open)执行,直接
绕过两个闸门(#1923)。插件是装进宿主的高权限代码,审批拦的是”意图”不是
“能力”。修复优先级:OS 级沙箱(Windows 走 CreateRestrictedToken 方向,
#1789)> 契约约束(pre-execute 必须是纯决策函数)> shell-launcher 白名单。
配套检测:dsh-plugin-doctor v1.9.0(pre-execute-side-effects)和 v1.11.0
(shell-launcher),明确标注为”审查辅助、不是沙箱”。