# Defense-in-Depth Score: DeepSeek Harness (dsh)

**Repo:** https://github.com/deepseek-ai/deepseek-harness · **Commit:** `5badb15009ae1756c3afe0ae0cef1faafc290ccc` (dsh-v0.2.1-alpha.1) · **Reviewed:** 2026-10-03
**What it is:** DeepSeek's plugin-based agent harness running a coding agent (developer preview)
**Category:** AI Assistants
**Scored configuration:** `npx @deepseek-ai/dsh web` on Linux with no flags: dsh-base + dsh-web-app bundles, the `standard` agent preset, sandbox mode workspace-write and approval policy ask.
**Agent surface (default):** code execution yes · filesystem write yes · network egress yes · external credentials yes · persistent memory yes · untrusted input yes · third party extensions opt-in · sub agents yes · external communication yes

## Score: 3.2 / 10.0 (Minimal)

| # | Criterion | S | C | D | B | Raw | Cap | Score | Confidence |
|---|---|---|---|---|---|---|---|---|---|
| C1 | Identity & least privilege | L1 | L1 | L2 | L0 | 0.25 | — | **0.25** | High |
| C2 | Approval gates | L3 | L1 | L3 | L0 | 0.45 | C2-POWERBYPASS | **0.25** | High |
| C3 | Tool & action scoping | L1 | L2 | L2 | L1 | 0.38 | — | **0.38** | High |
| C4 | Code-execution isolation | L2 | L1 | L1 | L0 | 0.28 | G2 | **0.25** | High |
| C5 | Untrusted input blast radius | L1 | L1 | L2 | L0 | 0.25 | C5-WORSTCASE | **0.25** | High |
| C6 | Memory, context & configuration integrity | L1 | L1 | L2 | L1 | 0.30 | C6-REPOCONFIG | **0.25** | High |
| C7 | Third-party extensions | L2 | L1 | L2 | L0 | 0.33 | — | **0.33** | Medium |
| C8 | Secrets & sensitive-data protection | L2 | L1 | L2 | L0 | 0.33 | — | **0.33** | High |
| C9 | Audit & traceability | L2 | L3 | L2 | L4 | 0.68 | — | **0.68** | High |
| C10 | Limits & kill switch | L1 | L1 | L1 | L0 | 0.20 | — | **0.20** | High |


DeepSeek Harness runs a capable coding agent inside a real but loose OS sandbox: writes are confined to the workspace, while the whole host filesystem stays readable and the network stays open. Its approval prompts are precise and fail closed, but they fire only when a command needs to write outside the workspace, so a hijacked agent can read your credentials and push, upload or delete over the network with no prompt. The sandbox is also not a complete boundary. Run it in a disposable VM or container without real credentials.

## Critical gaps
- The agent runs with the user's ambient authority: all credential files and the SSH agent socket are reachable from the default session, with open network egress. (ASI03, T3; C1) — [packages/sandbox/sandbox-local/src/profiles.ts:17](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/sandbox/sandbox-local/src/profiles.ts#L17); [packages/subprocess/subprocess/src/index.ts:47](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/subprocess/subprocess/src/index.ts#L47)
- The default approval gate only covers sandbox escalation: bash commands that push code or send data over the network run with no human approval. (ASI02, ASI09, T10; C2) — [packages/shell/tool-bash/src/index.ts:527](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/shell/tool-bash/src/index.ts#L527); [packages/sandbox/sandbox/src/escalation.ts:173](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/sandbox/sandbox/src/escalation.ts#L173); searched `rg -n 'unshare-net|--share-net|network'` in `packages/sandbox/sandbox-local/src/profiles.ts` → 0 hits (No network namespace or network rule in any runner profile (bwrap, Landlock, Seatbelt).)
- The default sandbox mounts the entire host filesystem (including home-directory credentials) read-only with unrestricted network. (ASI05, T11; C4) — [packages/sandbox/sandbox-local/src/profiles.ts:17](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/sandbox/sandbox-local/src/profiles.ts#L17); [packages/sandbox/sandbox-local/src/profiles.ts:20](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/sandbox/sandbox-local/src/profiles.ts#L20)
- A prompt-injected default session can both exfiltrate secrets and take irreversible actions with no human involved. (ASI01, T6, LLM01; C5) — [packages/shell/tool-bash/src/index.ts:527](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/shell/tool-bash/src/index.ts#L527); [packages/sandbox/sandbox-local/src/profiles.ts:17](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/sandbox/sandbox-local/src/profiles.ts#L17); [packages/web/tool-web/src/trust.ts:7](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/web/tool-web/src/trust.ts#L7)
- The launch directory's .env is materialised into the process environment and may supply the DeepSeek API key and other variables without a trust decision. (ASI06, ASI04, T1; C6) — [packages/boot/app-boot/src/index.ts:248](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/boot/app-boot/src/index.ts#L248); [packages/credentials/credentials-local/src/index.ts:19](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/credentials/credentials-local/src/index.ts#L19); [packages/boot/app-boot/src/index.ts:146](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/boot/app-boot/src/index.ts#L146)
- Installed plugins run in-process as host code outside the workspace sandbox with the harness's full authority. (ASI04, T17, LLM03; C7) — [packages/boot/plugin-manager/README.md:31](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/boot/plugin-manager/README.md#L31)
- Long-lived credentials (the stored DeepSeek key and home-directory credential files) are readable by the model and by every sandboxed command. (ASI03, LLM02, T9; C8) — [packages/sandbox/sandbox-local/src/profiles.ts:17](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/sandbox/sandbox-local/src/profiles.ts#L17); [packages/fs/fs-sandbox/src/index.ts:7](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/fs/fs-sandbox/src/index.ts#L7)

## Criterion details

### C1 Identity & least privilege — 0.25 (high)

The harness runs as the local user and narrows that authority only partly. Every child process gets an environment with credential-shaped variables (names containing KEY, PASSWORD, SECRET or TOKEN) removed, and the default sandbox stops shell writes outside the workspace. But the whole host filesystem stays readable, including SSH keys, cloud credential files and the harness's own stored DeepSeek key, the SSH agent socket is not removed, and network access is unrestricted. A hijacked agent can therefore use or steal the user's credentials across services.

- **S L1:** Ambient OS-user authority narrowed only by a name-pattern scrub of credential-shaped environment variables for subprocesses. — [packages/subprocess/subprocess/src/index.ts:47](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/subprocess/subprocess/src/index.ts#L47); [packages/subprocess/subprocess/src/index.ts:69](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/subprocess/subprocess/src/index.ts#L69); [packages/sandbox/sandbox-local/src/profiles.ts:17](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/sandbox/sandbox-local/src/profiles.ts#L17) (verified)
  - *To reach the next level:* No per-tool or per-capability credential scoping; credential files and the SSH agent socket remain usable.
- **C L1:** The scrub covers spawned processes, but in-process tools (the read tool) and sandboxed bash can still read every credential file the user can. — [packages/fs/fs-sandbox/src/index.ts:7](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/fs/fs-sandbox/src/index.ts#L7); searched `rg -n -i '\.ssh|\.aws|id_rsa|credentials'` in `packages/fs/tool-fs/src packages/fs/fs-sandbox/src` → 0 hits (No sensitive-path denial for the read tool.); [packages/sandbox/sandbox-local/src/profiles.ts:17](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/sandbox/sandbox-local/src/profiles.ts#L17) (verified)
  - *To reach the next level:* In-process tools and credential files are not routed through any scoping layer.
- **D L2:** The default is workspace-write plus ask, and widening needs the operator's DSH_PERMISSION_MODE variable, a UI preset change, or a per-call approval; a workspace .env cannot set DSH_* names. — [packages/bundle/base/cordis.patch.yml:232](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/bundle/base/cordis.patch.yml#L232); [packages/boot/app-boot/src/index.ts:157](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/boot/app-boot/src/index.ts#L157) (verified)
  - *To reach the next level:* The default still reads all host credentials and has open network; it is not near-minimal.
- **B L0:** With credential files readable and network egress open, a hijacked agent reaches the user's whole account across services (SSH, cloud, model API). — [packages/sandbox/sandbox-local/src/profiles.ts:17](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/sandbox/sandbox-local/src/profiles.ts#L17); searched `rg -n 'unshare-net|--share-net|network'` in `packages/sandbox/sandbox-local/src/profiles.ts` → 0 hits (No network namespace or network rule in any runner profile (bwrap, Landlock, Seatbelt).); searched `rg -n -i '\.ssh|\.aws|id_rsa|credentials'` in `packages/fs/tool-fs/src packages/fs/fs-sandbox/src` → 0 hits (No sensitive-path denial for the read tool.) (verified)
  - *To reach the next level:* Credentials would need to be out of reach or short-lived and scoped.
- **Cap:** none

### C2 Approval gates — 0.25 (high)

Approval in DeepSeek Harness is tied to the sandbox, not to actions. In the default workspace-write mode the model's shell commands, file edits, web fetches, reminders and sub-agents run with no human prompt; a human is asked only when a command or edit needs more filesystem access than the workspace (an escalation to full access). That escalation prompt is well built: it is per call, shows the exact tool call, grants only that one call, and fails closed if no one answers. But commands that use the network, such as git push or curl uploads, never reach it, and there is no undo for them.

- **S L3:** Escalation approvals are per call, attached to the exact streamed tool call, one-shot (allowed-once), and every non-grant outcome fails closed. — [packages/sandbox/sandbox/src/escalation.ts:188](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/sandbox/sandbox/src/escalation.ts#L188); [packages/sandbox/sandbox/src/escalation.ts:202](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/sandbox/sandbox/src/escalation.ts#L202); [packages/shell/tool-bash/src/index.ts:486](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/shell/tool-bash/src/index.ts#L486) (verified)
  - *To reach the next level:* No argument-level allow/deny/escalate policy on parsed commands.
- **C L1:** Only sandbox escalations are gated; bash runs any in-workspace or networked command, and web_fetch, schedule_create and delegation run, with no approval. — [packages/shell/tool-bash/src/index.ts:527](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/shell/tool-bash/src/index.ts#L527); searched `rg -n "'tools/pre-execute'"` in `packages/interaction packages/sandbox packages/shell` → 0 hits (No approval/permission pre-execute policy in the approval, sandbox, or shell packages; approval is reached only through sandbox escalation.); searched `rg -n 'unshare-net|--share-net|network'` in `packages/sandbox/sandbox-local/src/profiles.ts` → 0 hits (No network namespace or network rule in any runner profile (bwrap, Landlock, Seatbelt).) (verified)
  - *To reach the next level:* Consequential shell actions (network, in-workspace deletes) and other mutating tools bypass the gate.
- **D L3:** Ask is the shipped policy; disabling it needs the loudly named danger-full-access mode (env var or preset), no allow-rules persist, and delegated children are pinned to never. — [packages/bundle/base/cordis.patch.yml:248](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/bundle/base/cordis.patch.yml#L248); [packages/bundle/base/cordis.patch.yml:253-262](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/bundle/base/cordis.patch.yml#L253-L262); [packages/subagent/subagent/src/child-agent.ts:254](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/subagent/subagent/src/child-agent.ts#L254) (verified)
  - *To reach the next level:* Elevated presets are not time-bounded and the approver is not an authenticated principal beyond loopback access.
- **B L0:** Ungated bash with open network can force-push, upload or delete with no undo; workspace change tracking offers no rollback. — searched `rg -n 'unshare-net|--share-net|network'` in `packages/sandbox/sandbox-local/src/profiles.ts` → 0 hits (No network namespace or network rule in any runner profile (bwrap, Landlock, Seatbelt).); searched `rg -n -i 'revert|rollback|restore|undo'` in `packages/deliverables/workspace-changes/src` → 0 hits (Workspace change tracking only displays diffs; it offers no rollback.) (verified)
  - *To reach the next level:* No checkpoints/rollback or previews for external actions.
- **Cap:** C2-POWERBYPASS — In the default workspace-write + ask configuration the bash tool, the most powerful action path, runs networked and in-workspace commands without crossing the approval gate, which is consulted only for filesystem escalations.

### C3 Tool & action scoping — 0.38 (high)

Some tools are carefully scoped: the file-write tools canonicalise paths and refuse writes outside the workspace, and web_fetch only reaches public addresses, pins each connection and refuses cross-origin redirects. But the default tool set also includes a raw bash tool that accepts any command string, so a hijacked agent can step around those checks with ordinary shell commands. Write, exec, network, delegation and scheduling tools are all on by default in the standard preset.

- **S L1:** Raw bash command passthrough sits alongside good validators (realpath containment for writes, public-IP pinning for fetch). — [packages/shell/tool-bash/src/index.ts:385](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/shell/tool-bash/src/index.ts#L385); [packages/web/web-fetch-http/src/network.ts:100](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/web/web-fetch-http/src/network.ts#L100) (verified)
  - *To reach the next level:* The general shell is not replaced or bounded by narrow, validated tools.
- **C L2:** Most built-in tools validate inputs (fs write fence, web fetch, schedule rule checks). — [packages/web/web-fetch-http/src/network.ts:100](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/web/web-fetch-http/src/network.ts#L100); [packages/fs/fs-sandbox/src/index.ts:20-23](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/fs/fs-sandbox/src/index.ts#L20-L23) (verified)
  - *To reach the next level:* No central validation layer; bash and reads are unvalidated.
- **D L2:** Agent and permission presets are selectable (including a read-only sandbox preset), but the default standard preset enables bash, file write, web and delegation. — [packages/bundle/web-app/cordis.patch.yml:583](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/bundle/web-app/cordis.patch.yml#L583); [packages/bundle/web-app/presets/standard.patch.yml:22-23](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/bundle/web-app/presets/standard.patch.yml#L22-L23); [packages/bundle/web-app/presets/standard.patch.yml:153-157](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/bundle/web-app/presets/standard.patch.yml#L153-L157) (verified)
  - *To reach the next level:* Default tool set is not read-only.
- **B L1:** A misused bash call has full host read and network reach; only writes are limited to the workspace. — [packages/sandbox/sandbox-local/src/profiles.ts:17](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/sandbox/sandbox-local/src/profiles.ts#L17); searched `rg -n 'unshare-net|--share-net|network'` in `packages/sandbox/sandbox-local/src/profiles.ts` → 0 hits (No network namespace or network rule in any runner profile (bwrap, Landlock, Seatbelt).) (verified)
  - *To reach the next level:* No quantity bounds and no network scoping.
- **Cap:** none

### C4 Code-execution isolation — 0.25 (high)

Shell commands, Node code and workflow scripts run inside an OS sandbox (bubblewrap or Landlock on Linux, Seatbelt on macOS, a restricted token on Windows) that limits writes to the workspace and fails closed if no sandbox is available. The sandbox is basic: the whole host filesystem is mounted readable, network is unrestricted, and there is no seccomp filter. More seriously, the sandbox is not a complete boundary. Even so, sandboxed code can read home-directory secrets and send them anywhere.

- **S L2:** bwrap with a read-only root bind, PID namespace, writable workspace bind and tmpfs /tmp; Seatbelt is allow-default with file writes denied. — [packages/sandbox/sandbox-local/src/profiles.ts:17](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/sandbox/sandbox-local/src/profiles.ts#L17); [packages/sandbox/sandbox-local/src/profiles.ts:20](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/sandbox/sandbox-local/src/profiles.ts#L20); [packages/sandbox/sandbox-local/src/profiles.ts:52](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/sandbox/sandbox-local/src/profiles.ts#L52); searched `rg -n 'unshare-net|--share-net|network'` in `packages/sandbox/sandbox-local/src/profiles.ts` → 0 hits (No network namespace or network rule in any runner profile (bwrap, Landlock, Seatbelt).) (verified)
  - *To reach the next level:* Network is not denied and there is no seccomp/no-new-privileges hardening.
- **C L1:** Bash, PTC and workflow go through ctx.sandbox, but not every model-influenced execution path is confined. — searched `rg -n -i 'sandbox|confine'` in `packages/subprocess/subprocess-local/src/index.ts` → 0 hits (The host subprocess service applies no confinement itself.) (verified)
  - *To reach the next level:* Confine every model-influenced execution path.
- **D L1:** Sandboxing is on by default and fails closed, but it can be defeated from inside the sandbox. — [packages/bundle/base/cordis.patch.yml:232](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/bundle/base/cordis.patch.yml#L232) (verified)
  - *To reach the next level:* The default boundary must not be defeatable from inside the sandbox.
- **B L0:** The home directory (including ~/.ssh and ~/.aws) is mounted read-only into the sandbox with full network egress. — [packages/sandbox/sandbox-local/src/profiles.ts:17](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/sandbox/sandbox-local/src/profiles.ts#L17); searched `rg -n 'unshare-net|--share-net|network'` in `packages/sandbox/sandbox-local/src/profiles.ts` → 0 hits (No network namespace or network rule in any runner profile (bwrap, Landlock, Seatbelt).) (verified)
  - *To reach the next level:* Home and credential paths should be hidden and egress denied or allowlisted.
- **Cap:** G2 — A workspace-controlled file can defeat the sandbox boundary.
- **Notes:** Not every model-influenced execution path is confined.

### C5 Untrusted input blast radius — 0.25 (high)

Fetched web pages and search results get a fixed notice telling the model to treat them as untrusted data, and nothing more. Reading files, tool output or sub-agent results does not change what the agent may do afterwards. A hijacked agent in the default session can read credentials and private files and send them out through bash or web_fetch, and can push or delete with no human involved.

- **S L1:** Only a textual untrusted-content notice on web results; no taint-driven gating. — [packages/web/tool-web/src/trust.ts:7](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/web/tool-web/src/trust.ts#L7); [packages/web/tool-web/src/fetch.ts:329](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/web/tool-web/src/fetch.ts#L329) (verified)
  - *To reach the next level:* No Rule-of-Two enforcement after untrusted content is read.
- **C L1:** The notice covers web fetch/search only; files, tool and sub-agent results are not distinguished. — [packages/web/tool-web/src/search.ts:74](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/web/tool-web/src/search.ts#L74) (verified)
  - *To reach the next level:* Other untrusted sources are not labelled or gated.
- **D L2:** The notice is hard-coded and always on. — [packages/web/tool-web/src/trust.ts:7](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/web/tool-web/src/trust.ts#L7) (verified)
  - *To reach the next level:* Capped by strength; nothing structural to keep on.
- **B L0:** Unattended exfiltration (bash/curl, web_fetch GET to any public host) plus irreversible actions (push, delete) are both possible. — [packages/shell/tool-bash/src/index.ts:527](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/shell/tool-bash/src/index.ts#L527); searched `rg -n 'unshare-net|--share-net|network'` in `packages/sandbox/sandbox-local/src/profiles.ts` → 0 hits (No network namespace or network rule in any runner profile (bwrap, Landlock, Seatbelt).); [packages/web/web-fetch-http/src/network.ts:100](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/web/web-fetch-http/src/network.ts#L100) (verified)
  - *To reach the next level:* Egress or irreversible actions would need human approval after untrusted input.
- **Cap:** C5-WORSTCASE — Worst case (B L0): a hijacked agent can leak data and take irreversible actions unattended.

### C6 Memory, context & configuration integrity — 0.25 (high)

Project files can steer the agent across sessions. AGENTS.md/CLAUDE.md and project skills under .agents/skills load automatically, and the agent can write them itself. The model can also create recurring reminders that survive restarts and re-prompt the agent, with no approval. The harness blocks a long list of dangerous startup variables (DSH_*, PATH, NODE_OPTIONS, base URLs, proxies) from a project .env. But the .env in the launch directory is still loaded into the process environment, can supply the model API key; the denylist does not cover every path.

- **S L1:** Instruction files and project skills load silently; reminders are model-written without gating; the project .env is materialised with a denylist only. — [packages/context/agent-instructions/src/config.ts:12](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/context/agent-instructions/src/config.ts#L12); [packages/skill/skill-filesystem/src/index.ts:251](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/skill/skill-filesystem/src/index.ts#L251); [packages/boot/app-boot/src/index.ts:248](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/boot/app-boot/src/index.ts#L248); [packages/boot/app-boot/src/index.ts:157](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/boot/app-boot/src/index.ts#L157) (verified)
  - *To reach the next level:* Project .env should not supply credentials or arbitrary environment; memory writes need gating.
- **C L1:** Only bootstrap-named variables are controlled; instruction files, skills, reminders and non-denylisted env names are not. — [packages/boot/app-boot/src/index.ts:146](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/boot/app-boot/src/index.ts#L146); [packages/bundle/web-app/presets/standard.patch.yml:36-37](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/bundle/web-app/presets/standard.patch.yml#L36-L37) (verified)
  - *To reach the next level:* Instruction files, skills and the schedule store are uncontrolled.
- **D L2:** Reminders are scoped to their session and delegated children cannot use them; single-user local storage. — [packages/schedule/schedule/src/runtime.ts:120](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/schedule/schedule/src/runtime.ts#L120); [packages/bundle/web-app/presets/standard.patch.yml:101-106](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/bundle/web-app/presets/standard.patch.yml#L101-L106) (verified)
  - *To reach the next level:* No retention limits or model-proof namespace isolation beyond session scoping.
- **B L1:** An agent-written AGENTS.md or reminder persists across the user's sessions/restarts and drives tool use. — [packages/context/agent-instructions/src/config.ts:12](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/context/agent-instructions/src/config.ts#L12); [packages/schedule/schedule/src/runtime.ts:120](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/schedule/schedule/src/runtime.ts#L120) (verified)
  - *To reach the next level:* Persisted context would need review or to be limited to text-only influence.
- **Cap:** C6-REPOCONFIG — The launch directory's .env is auto-loaded into process.env without a trust decision and may supply the model API credential (credentials-local documents that the invoking project may supply a key) and other variables not covered by the denylist.

### C7 Third-party extensions — 0.33 (medium)

No third-party plugin or MCP server is enabled by default, the model-facing plugin_manager tool is off in the standard preset, and extensions can only be added from user scope (the Plugins page or the profile patch), not from the workspace. Installs go through pnpm with a lockfile, and pnpm blocks dependency build scripts until approved. But installed plugins run as host code inside the harness process with everything it can reach, outside the sandbox, and nothing verifies signatures or re-approves updates.

- **S L2:** pnpm installs record versions in the profile lockfile; integrity checking is pnpm's, not the manager's. — searched `rg -n -i 'integrity|signature|sha512'` in `packages/boot/plugin-manager/src` → 2 hits (Both hits only classify pnpm's own tarball-integrity failure messages; the manager does no signature or allowlist verification itself.) (inferred)
  - *To reach the next level:* No harness-side signature/allowlist verification or rug-pull re-approval.
- **C L1:** Bundles go through the manager; MCP servers configured in patches are launched as given. — searched `rg -n 'dsh-mcp-client'` in `packages/bundle/base/cordis.patch.yml packages/bundle/web-app/cordis.patch.yml packages/bundle/web-app/presets/standard.patch.yml` → 0 hits (No MCP client composed in the default web profile.); [packages/boot/plugin-manager/README.md:31](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/boot/plugin-manager/README.md#L31) (verified)
  - *To reach the next level:* Verification does not extend to MCP servers or update paths.
- **D L2:** Nothing third-party is on by default, the tool is disabled, and only user scope adds extensions; the install flow shows package metadata but not permissions. — [packages/bundle/web-app/presets/standard.patch.yml:160-162](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/bundle/web-app/presets/standard.patch.yml#L160-L162); [packages/boot/plugin-manager/README.md:31](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/boot/plugin-manager/README.md#L31) (verified)
  - *To reach the next level:* Install does not show the exact code/permissions that will run.
- **B L0:** Installed host code runs in-process outside the sandbox with the harness's full authority. — [packages/boot/plugin-manager/README.md:31](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/boot/plugin-manager/README.md#L31) (verified)
  - *To reach the next level:* Extensions would need their own process, scrubbed env, or sandbox.
- **Cap:** none

### C8 Secrets & sensitive-data protection — 0.33 (high)

Stored credentials live in a plaintext file that must be private to its owner (the harness refuses to start otherwise), and subprocesses get an environment with credential-shaped variables removed. Telemetry uploads part of a session log to DeepSeek only when the user submits feedback, but the shipped redaction step has no rules. Session transcripts and model-bound tool output are not redacted. The read tool and sandboxed bash can read the stored key file and other credential files and put them into the model's context.

- **S L2:** Credentials file written 0600 with a startup permission check; env-name scrub for subprocesses. — [packages/credentials/credentials-local/src/index.ts:691](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/credentials/credentials-local/src/index.ts#L691); [packages/subprocess/subprocess/src/index.ts:47](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/subprocess/subprocess/src/index.ts#L47) (verified)
  - *To reach the next level:* No keychain/encryption and no redaction before transcripts or model-bound messages.
- **C L1:** Only subprocess environments are protected; transcripts, telemetry and model-bound content are not redacted. — [packages/session/session-telemetry/src/coordinator.ts:199](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/session/session-telemetry/src/coordinator.ts#L199); [packages/subprocess/subprocess/src/index.ts:69](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/subprocess/subprocess/src/index.ts#L69) (verified)
  - *To reach the next level:* Logs, transcripts and telemetry lack redaction.
- **D L2:** Telemetry ships in FEEDBACK_ONLY mode (session log sent only on explicit feedback) and can be disabled by env. — [packages/bundle/base/cordis.patch.yml:207](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/bundle/base/cordis.patch.yml#L207); [packages/bundle/base/cordis.patch.yml:211](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/bundle/base/cordis.patch.yml#L211); [packages/session/session-telemetry/src/coordinator.ts:199](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/session/session-telemetry/src/coordinator.ts#L199) (verified)
  - *To reach the next level:* Redaction is not on by default (no rules shipped).
- **B L0:** The long-lived DeepSeek key file and the user's credential files are readable by the model and every sandboxed subprocess. — [packages/sandbox/sandbox-local/src/profiles.ts:17](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/sandbox/sandbox-local/src/profiles.ts#L17); searched `rg -n -i '\.ssh|\.aws|id_rsa|credentials'` in `packages/fs/tool-fs/src packages/fs/fs-sandbox/src` → 0 hits (No sensitive-path denial for the read tool.) (verified)
  - *To reach the next level:* Keys would need to be unreachable or short-lived.
- **Cap:** none

### C9 Audit & traceability — 0.68 (high)

Every tool call is written to a durable session log in the harness home before it runs, and approval questions and answers are logged as paired events. The log is flushed before each top-level tool runs, and a failed flush stops the tool, so actions don't run unrecorded. Sub-agents keep their own session logs. The log is plain JSONL with no hash chain or off-host shipping, it does not name the approver, and code that escapes the sandbox could edit it.

- **S L2:** Structured tool/call events with arguments and paired approval/asked/decided events in the session log. — [packages/core/agent-loop/src/tool-calls.ts:264](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/core/agent-loop/src/tool-calls.ts#L264); [packages/interaction/user-approval/src/index.ts:225](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/interaction/user-approval/src/index.ts#L225); [packages/interaction/user-approval/src/index.ts:232](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/interaction/user-approval/src/index.ts#L232) (verified)
  - *To reach the next level:* No approver identity, no tamper evidence, no standard export by default.
- **C L3:** All registry tool calls (built-in, delegated children) and approvals are recorded; sandbox and permission changes are session events. — [packages/core/agent-loop/src/tool-calls.ts:264](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/core/agent-loop/src/tool-calls.ts#L264); [packages/interaction/user-approval/src/index.ts:232](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/interaction/user-approval/src/index.ts#L232) (verified)
  - *To reach the next level:* Credential use and memory/config writes are not recorded.
- **D L2:** On by default under $DSH_HOME/sessions, outside the workspace and the sandbox's write set. — [packages/bundle/base/cordis.patch.yml:133](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/bundle/base/cordis.patch.yml#L133); [packages/sandbox/sandbox-local/src/profiles.ts:20](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/sandbox/sandbox-local/src/profiles.ts#L20) (verified)
  - *To reach the next level:* The C4 sandbox gap or a home-directory workspace lets model-influenced code alter it.
- **B L4:** Top-level tool dispatch waits on a durability flush and fails closed if it throws. — [packages/session/session-checkpoint-policy/src/index.ts:72](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/session/session-checkpoint-policy/src/index.ts#L72); [packages/session/session-checkpoint-policy/src/index.ts:58](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/session/session-checkpoint-policy/src/index.ts#L58) (verified)
- **Cap:** none

### C10 Limits & kill switch — 0.20 (high)

The agent loop has no step, turn, wall-clock or token budget. Bash calls have a 60-second default timeout (10-minute cap), but a command that times out moves to the background and keeps running, and background commands have no timeout at all. Sub-agents are capped at depth 1 and 8 active, and workflows at 1,000 agents. Stopping a turn kills the foreground command, but background jobs and scheduled reminders keep going.

- **S L1:** Only per-execution timeouts and delegation caps exist; no iteration, time or cost cap on the loop. — searched `rg -n -i 'maxSteps|maxTurns|max_steps|max_turns|stepLimit|turnLimit'` in `packages/core/agent-loop/src packages/core/agent/src` → 0 hits (The agent loop has no step, turn, or token-budget cap.); [packages/bundle/base/cordis.patch.yml:239](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/bundle/base/cordis.patch.yml#L239); [packages/shell/bash-local/src/index.ts:103](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/shell/bash-local/src/index.ts#L103) (verified)
  - *To reach the next level:* No iteration cap plus wall-clock or token cap.
- **C L1:** Limits cover delegation counts and foreground tool waits, not the loop or background jobs. — [packages/subagent/subagent/src/index.ts:200-201](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/subagent/subagent/src/index.ts#L200-L201); [packages/workflow/workflow-ptc/src/index.ts:108](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/workflow/workflow-ptc/src/index.ts#L108); [packages/shell/tool-bash/src/index.ts:394](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/shell/tool-bash/src/index.ts#L394) (verified)
  - *To reach the next level:* Top-level loop is unbounded.
- **D L1:** Defaults exist but timeouts promote to unbounded background jobs, and the model chooses run_in_background. — [packages/shell/tool-bash/src/index.ts:58](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/shell/tool-bash/src/index.ts#L58); [packages/shell/tool-bash/src/index.ts:394](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/shell/tool-bash/src/index.ts#L394) (verified)
  - *To reach the next level:* Defaults must actually bound runtime and resist model escape.
- **B L0:** A runaway loop can continue indefinitely; background jobs and reminders outlive a stop. — searched `rg -n -i 'maxSteps|maxTurns|max_steps|max_turns|stepLimit|turnLimit'` in `packages/core/agent-loop/src packages/core/agent/src` → 0 hits (The agent loop has no step, turn, or token-budget cap.); [packages/shell/tool-bash/src/index.ts:394](https://github.com/deepseek-ai/deepseek-harness/blob/5badb15009ae1756c3afe0ae0cef1faafc290ccc/packages/shell/tool-bash/src/index.ts#L394) (verified)
  - *To reach the next level:* Hard ceilings and stop-everything halt are missing.
- **Cap:** none

## Rule-of-Two check
[A] untrusted input: web_fetch/web_search and workspace files enter context (packages/web/tool-web/src/fetch.ts:329) · [B] sensitive data/systems: entire host filesystem readable, incl. ~/.ssh and $DSH_HOME/.credentials.yaml (packages/sandbox/sandbox-local/src/profiles.ts:17) · [C] state change / egress: bash with open network and workspace writes, no approval (packages/shell/tool-bash/src/index.ts:527) · Same default session? Yes

## Highest-impact improvements
1. Deny network in the default sandbox profile (bwrap --unshare-net, Seatbelt network deny) and require approval to escalate network access. — C5 B L0→L2, +0.100 before caps (Playbook 1)
2. Harden the sandbox boundary so that no model-influenced path executes outside it. — C4 C L1→L3, +0.150 before caps (Playbook 3)
3. Hide home-directory credential paths and $DSH_HOME from the sandbox (tmpfs over $HOME, bind only the workspace and toolchains). — C4 B L0→L2, +0.100 before caps (Playbook 3)
4. Stop materialising the launch directory .env into process.env and stop accepting credentials from it without an explicit trust prompt. — C6 S L1→L2, +0.075 before caps (Playbook 2)
5. Add a default per-turn step and token budget, and kill promoted/background jobs when the user stops a turn. — C10 S L1→L2, +0.075 before caps (Playbook 3 step 3)

## Re-audit log
- No changes.

## Limitations
- Static source review of the pinned commit only; nothing was executed, installed, or probed.
- Scored the Linux Web profile; macOS Seatbelt, Windows restricted-token, desktop, ACP and headless profiles and the experimental Auto review preset were not scored in depth.
- The C4 sandbox finding relies partly on documented third-party behaviour; it was not exercised.
- pnpm lockfile integrity behaviour for plugin installs is inferred from pnpm's documented behaviour, not verified in this repo.
- The repository is ~14k files; review focused on bundle composition, tool registration, sandbox, approval, credentials, persistence and limits packages. Vendored Cordis, the Python SDK, and client UI rendering (e.g. markdown image auto-loading as an exfil channel) were not examined.
- No reviewer-directed prompt-injection text was found in the repository.
