DeepSeek Harness permissions and sandbox: trace every tool call before granting access
Quick answer
DeepSeek Harness does not implement tool safety as one permission switch. At the source snapshot checked for this guide—default branch master, commit 141eb6fef83422698aef7a981029e843e8161534—a tool call moves through distinct policy, approval, execution, filesystem, and result stages:
tool/call is logged and shown as pending
-> tools/pre-execute: allow | deny | ask
-> ask: only allowed-once opens this call
-> monotonic guards: deny or abstain
-> tools/execute: timeout/retry/metrics wrappers
-> tool body and any fs write/edit intent gate
-> tools/post-execute: accept, replace, add context, or block
-> normalize -> finalizeContent -> frozen tools/result
-> durable tool/result and completed UI card
The practical default is workspace-write plus ask. It limits file effects to the session workspace and supported temporary areas, while operations marked ask need a one-shot decision. But the sandbox vocabulary covers filesystem effects only. It does not promise network isolation or restricted process visibility.
DeepSeek Harness remains a Developer Preview with compatibility-breaking changes expected. GitHub currently has the dsh-v0.1.0-rc.8 pre-release at this commit, while npm still reports @deepseek-ai/dsh@0.1.0-rc.7. Recheck and pin the exact artifact you test.
Who this is for
This guide is for agent-framework developers and security-minded teams evaluating how DeepSeek Harness approves tools, confines local commands, protects file edits, and records outcomes. If you have not isolated DSH_HOME and a disposable workspace yet, start with the Developer Preview install and rollback checklist. For why these layers are separate plugins, see the Cordis architecture guide.
Four controls that must not be collapsed into one
| Control | Values or decisions | What it controls | What it does not prove |
|---|---|---|---|
| Pre-execute policy | allow, deny, ask |
Whether this call reaches dispatch | OS-level confinement |
| Approval policy | ask, never |
Whether an ask reaches an answerer |
That an allowed call is safe |
| Sandbox mode | read-only, workspace-write, danger-full-access |
Filesystem effects for enforcing capabilities | Network or process isolation |
| Filesystem observation | unseen, absent, present-at-version | Read-before-edit and no-clobber freshness | General authorization or persistence across resume |
The shipped permission-preset table bundles two independent knobs. workspace-write means sandbox workspace-write plus approval ask. danger-full-access means no file confinement plus approval never. That second preset does not mean “allow everything”: any policy that returns ask is automatically rejected, while calls already classified allow can run without filesystem confinement.
There is no shipped read-only named preset in the documented default table. A deployment can configure different presets or produce the derived custom state by changing the sandbox and approval knobs independently.
Why the approval path fails closed
An ask opens only when ctx.approval.request() returns allowed-once. Explicit rejection, cancellation, an unavailable channel, a missing agent, a missing approval service, a throwing answerer, or a non-conforming outcome all deny the call. The request and decision are appended as the log-only approval/asked and approval/decided pair inside the open turn.
After approval, registered guards still run. A guard can return a denial reason or abstain; it has no “allow” result. That monotonic design prevents later listener ordering from reopening a call an owner policy denied. Denied calls skip the tool body but still enter post-execute policy, so auditing or corrective feedback can observe a single final outcome.
The sandbox boundary is narrower than its name
The three modes describe file effects:
read-onlydenies mutations, apart from required sinks such as/dev/nullon POSIX runners.workspace-writepermits writes below the canonical session workspace and backend-defined temporary roots.danger-full-accessbypasses confinement and does not call the sandbox provider.
The local provider selects Linux Bubblewrap before Landlock, macOS Seatbelt, and a Windows restricted-token/ACL backend. Reported enforcement can be full or partial; older Landlock ABIs and the current Windows ACL boundary are documented partial cases. An unsupported platform or unusable runner must surface SANDBOX_UNAVAILABLE, not silently run the original command.
Treat this as file-effect containment, not an internet-deny control. If an untrusted repository must not reach the network, add a separate egress boundary and verify it independently, as described in the untrusted-repository sandbox checklist.
Filesystem edits add freshness, not broader permission
The filesystem observation plugin records whether the active session has seen a target absent or present at a version. Editing an unseen file returns FS_NOT_OBSERVED; editing a known-missing file returns FS_NOT_FOUND; editing a changed file fails the provider's compare-and-swap check. A write to an observed file uses replaceIfVersion, while an unseen or absent target uses createIfAbsent.
This state is session-owned and in memory. It is cleared on plugin disposal and does not survive resume, so resumed sessions must read again. A direct ctx.fs read does not emit fs/observed, and even a windowed read authorizes a full-file overwrite only if the version is unchanged. This is a no-clobber mechanism, not proof that the model reviewed every line.
Nine fail-closed canaries
Run these with harmless fixtures in a disposable workspace before touching a real repository.
| Canary | Expected evidence | Stop condition |
|---|---|---|
| 1. Preset projection | New session reports workspace-write + ask |
UI label and effective knobs disagree |
| 2. One-shot approval | One allowed-once call runs and logs one matched audit pair |
Grant persists to a second call |
| 3. Missing answerer | ask becomes unavailable/denied and the body never runs |
Missing UI opens the gate |
| 4. Never policy | ask is rejected without dispatching an answerer |
Headless run waits or proceeds |
| 5. Read-only mutation | Workspace and temp write fixtures are denied | Any ordinary file mutation succeeds |
| 6. Workspace containment | In-root write succeeds; parent and symlink-escape writes fail | Canonical escape reaches the filesystem |
| 7. Runner failure | Missing/refused runner returns SANDBOX_UNAVAILABLE |
Command runs unconfined |
| 8. Enforcement report | Partial backend remains labeled partial |
Partial is promoted to full |
| 9. Fresh edit | Read → edit works; external change → same edit returns stale and requires reread | Stale content is overwritten |
Add one deliberate network negative control: show that the file sandbox alone does not block a harmless outbound probe. The correct result is evidence that a separate egress policy is still required—not a reason to run a real exfiltration test.
Common mistakes
- Calling
aska persistent permission grant. The only positive outcome is one-shot. - Treating
neveras “auto-approve.” It auto-rejects asks. - Assuming
workspace-writeblocks network access or hides processes. - Treating Windows ACL or older Landlock enforcement as equivalent to a reported full backend.
- Putting authorization into
tools/post-execute. By then the side effect may already have happened; post-execute is for final acceptance, replacement, context, or blocking the result. - Assuming result text is mutable audit evidence. The registry normalizes and freezes the authoritative outcome before
tools/resultobservers receive it. - Assuming read-before-edit survives resume. The current observation map is not persisted.
FAQ
What is the safest starting preset?
For interactive trials, the documented default workspace-write + ask is the reasonable baseline, combined with a disposable workspace and separate network controls. A stricter unattended composition should explicitly define its sandbox and approval policy and prove every denied path; do not infer it from a UI label.
Can post-execute undo an unsafe tool action?
No. It can replace or block the result seen by the model, but ordinary side effects are not transactional. Authorization and confinement must happen before or during dispatch.
Does an approval make danger-full-access safe?
No. Approval answers whether one action may proceed; it does not shrink the action's filesystem, network, credential, or process reach.
Is rc.8 installable from npm?
At the August 20 check, GitHub published dsh-v0.1.0-rc.8 and the repository was at that tag, while npm latest/next remained rc.7. Pin the registry artifact you actually verify.
Sources
- DeepSeek Harness repository and Developer Preview boundary
- dsh-v0.1.0-rc.8 pre-release
- npm: @deepseek-ai/dsh 0.1.0-rc.7
- Tool execution pipeline at commit 141eb6f
- Permission presets at commit 141eb6f
- Approval contract at commit 141eb6f
- Process sandbox contract at commit 141eb6f
- Tool runtime source at commit 141eb6f
- User approval source at commit 141eb6f
- Filesystem observation policy source at commit 141eb6f
- Filesystem sandbox source at commit 141eb6f
- Local sandbox provider source at commit 141eb6f