# Defense-in-Depth Score: Codewhale

**Repo:** https://github.com/Hmbown/Codewhale · **Commit:** `b131357276568aa969d573129efa0d77c09f68cd` · **Reviewed:** 2026-10-05
**What it is:** Open-source Rust terminal coding agent (formerly DeepSeek-TUI)
**Category:** Coding
**Scored configuration:** Interactive `codewhale` TUI on Linux, fresh install, no flags, Work mode with the default Ask permission posture (no prefer_bwrap, telemetry and memory at defaults).
**Agent surface (default):** code execution yes · filesystem write yes · network egress yes · external credentials yes · persistent memory opt-in · untrusted input yes · third party extensions opt-in · sub agents yes · external communication opt-in

## Score: 4.5 / 10.0 (Minimal)

| # | Criterion | S | C | D | B | Raw | Cap | Score | Confidence |
|---|---|---|---|---|---|---|---|---|---|
| C1 | Identity & least privilege | L1 | L2 | L2 | L1 | 0.38 | — | **0.38** | High |
| C2 | Approval gates | L3 | L2 | L3 | L2 | 0.62 | — | **0.62** | High |
| C3 | Tool & action scoping | L2 | L2 | L1 | L1 | 0.40 | — | **0.40** | High |
| C4 | Code-execution isolation | L3 | L1 | L2 | L2 | 0.50 | G1 | **0.50** (alt) | High |
| C5 | Untrusted input blast radius | L2 | L2 | L2 | L2 | 0.50 | — | **0.50** | High |
| C6 | Memory, context & configuration integrity | L2 | L2 | L3 | L1 | 0.50 | C6-REPOCONFIG | **0.25** | High |
| C7 | Third-party extensions | L2 | L1 | L1 | L2 | 0.38 | — | **0.38** | High |
| C8 | Secrets & sensitive-data protection | L2 | L3 | L1 | L1 | 0.47 | — | **0.47** | High |
| C9 | Audit & traceability | L2 | L3 | L2 | L2 | 0.57 | — | **0.57** | High |
| C10 | Limits & kill switch | L2 | L2 | L1 | L1 | 0.40 | — | **0.40** | High |


Codewhale asks before every shell command that is not a carefully parsed read-only one, before every web fetch or search, and before MCP tools with side effects, and it strips secrets from the environment of everything it launches. The dominant risk on Linux is that approved commands run with no OS sandbox by default, so one wrongly approved command can reach your whole home directory; on macOS a Seatbelt sandbox is applied automatically. File edits inside a git repository run without a prompt, AGENTS.md loads silently, and turns have no step, time or spend limit by default.

## Critical gaps
- A workspace .env is auto-loaded at startup, before any trust decision, and can supply model-provider and sandbox-service API keys that Codewhale uses when the user has not configured their own. (ASI06, ASI04; C6) — [crates/tui/src/lib.rs:2020](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/lib.rs#L2020); [crates/tui/src/lib.rs:3108-3121](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/lib.rs#L3108-L3121); [crates/tui/src/lib.rs:3086-3103](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/lib.rs#L3086-L3103)
- On Linux, model-requested shell commands run unsandboxed by default (bubblewrap is opt-in and silently skipped if missing), with the user's full home directory in reach. (ASI05; C4) — [crates/tui/src/sandbox/mod.rs:349-362](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/sandbox/mod.rs#L349-L362); [crates/tui/src/tui/ui/frame.rs:1029](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tui/ui/frame.rs#L1029); [crates/tui/src/sandbox/mod.rs:661-673](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/sandbox/mod.rs#L661-L673)

## Criterion details

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

Codewhale runs as you and does not get a scoped identity of its own, but it narrows what its child processes inherit: every shell command, test runner, language server and MCP server starts from a cleared environment with a short allowlist of non-secret variables, so API keys and tokens in your shell are not passed on. Your home directory is still reachable, though, so credential files on disk (cloud configs, the gh login, SSH keys) remain usable by any command you approve, and on Linux nothing confines those commands. Widening (Full Access, trust mode) is an explicit user choice.

- **S L1:** Ambient OS-user authority, narrowed only by an allowlist-based environment scrub for every child process. — [crates/tui/src/child_env.rs:100-106](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/child_env.rs#L100-L106); [crates/tui/src/child_env.rs:278-294](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/child_env.rs#L278-L294) (verified)
  - *To reach the next level:* No per-tool or per-capability credential scoping; on-disk credential files under HOME remain usable by child commands.
- **C L2:** Built-in shell, test runners and language servers use the scrubbed environment; MCP servers get a slightly wider allowlist (AWS profile/region selection, package-manager paths). — [crates/tui/src/child_env.rs:527-556](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/child_env.rs#L527-L556); [crates/tui/src/mcp/stdio.rs:169-180](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/mcp/stdio.rs#L169-L180) (verified)
  - *To reach the next level:* No authorization layer in code that every tool path, extension and sub-agent passes through.
- **D L2:** Default Ask posture with workspace-scoped file tools; Full Access and trust mode widen authority on an explicit user action. — [crates/execpolicy/src/approval_mode.rs:11-16](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/execpolicy/src/approval_mode.rs#L11-L16); [crates/tui/src/core/authority.rs:456-474](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/core/authority.rs#L456-L474) (verified)
  - *To reach the next level:* Widening is not time-bounded and does not revert automatically.
- **B L1:** A hijacked agent holds the user's full local authority, including credential files on disk; the surviving independent layer is the per-call human approval on shell and network tools. — [crates/tui/src/child_env.rs:278-294](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/child_env.rs#L278-L294); [crates/tui/src/tools/shell.rs:5659-5665](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/shell.rs#L5659-L5665) (verified)
  - *To reach the next level:* Credentials reachable from the agent are not limited to one system or to read-only use.
- **Cap:** none

### C2 Approval gates — 0.62 (high)

In the default Ask posture every shell command needs your approval, except a short, carefully parsed allowlist of read-only commands (cat, ls, rg, git status/log/diff and read-only gh queries) that refuses pipes, redirects, substitutions and unknown options. Web fetch and search also ask every time, and MCP tools with side effects ask. The approval card shows the exact command or file content. The main exception is file edits: inside a git repository, writes to project files run without a prompt (credential files, .git and .codewhale are excluded), relying on git and snapshots for undo. Full Access is one Shift+Tab away and turns prompts off; a repository cannot loosen any of this.

- **S L3:** Per-call approval rendering the exact command, file content or diff, with risk/stakes tiers and typed allow/deny/ask rules. — [crates/tui/src/tui/approval/previews.rs:15-25](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tui/approval/previews.rs#L15-L25); [crates/tui/src/tools/approval_cache.rs:1-6](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/approval_cache.rs#L1-L6); [crates/tui/src/core/authority.rs:456-474](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/core/authority.rs#L456-L474) (verified)
  - *To reach the next level:* Session approvals are scoped by an arity-aware command-family key, so an approved call can cover later variants; no argument-level policy on every approval.
- **C L2:** Shell, network, test-runner and side-effecting MCP tools are gated, sub-agent holds are routed to the parent's prompt, and auto-approved shell commands are a parsed read-only allowlist. — [crates/tui/src/tools/shell.rs:5659-5665](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/shell.rs#L5659-L5665); [crates/execpolicy/src/command_safety.rs:515-545](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/execpolicy/src/command_safety.rs#L515-L545); [crates/execpolicy/src/command_safety.rs:1444-1455](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/execpolicy/src/command_safety.rs#L1444-L1455); [crates/tui/src/core/authority.rs:486-495](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/core/authority.rs#L486-L495); [crates/tui/src/core/engine/turn_loop.rs:3645-3667](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/core/engine/turn_loop.rs#L3645-L3667); [crates/tui/src/tools/fetch_url.rs:143-147](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/fetch_url.rs#L143-L147) (verified)
  - *To reach the next level:* In-workspace file writes in a git repository bypass the human prompt by policy, so not every state-changing path reaches a person.
- **D L3:** Ask is the default posture; project config can only tighten approval, and the bypass value is not accepted from config.toml's approval_policy. — [crates/execpolicy/src/approval_mode.rs:11-16](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/execpolicy/src/approval_mode.rs#L11-L16); [crates/config/src/lib.rs:3843-3852](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/config/src/lib.rs#L3843-L3852); [crates/config/src/lib.rs:3793-3797](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/config/src/lib.rs#L3793-L3797) (verified)
  - *To reach the next level:* Full Access is a single keypress, not session- or time-bounded, and approval is not tied to an authenticated principal.
- **B L2:** Workspace edits are recoverable through git and side-git snapshots; an approved shell or network command on Linux can make irreversible changes anywhere the user can. — [crates/tui/src/tools/shell.rs:4196-4206](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/shell.rs#L4196-L4206); [crates/tui/src/core/authority.rs:591-603](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/core/authority.rs#L591-L603) (verified)
  - *To reach the next level:* No dry-run or preview for external actions, and no rate limit on consequential actions.
- **Cap:** none

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

The file tools check that paths stay inside the workspace after resolving symlinks, and web fetches go through an SSRF guard that blocks private and cloud-metadata addresses, pins DNS and rechecks redirects. But the main tool is a general shell that accepts any command string; only the auto-approval classifier is an allowlist. Shell, file write and network tools are all available by default in Work mode (Plan mode is read-only), and on Linux a misused approved command reaches the whole machine.

- **S L2:** Resolved-path containment for file tools and an SSRF guard for fetches, but the shell takes an arbitrary command string. — [crates/tui/src/tools/web/guard.rs:1-7](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/web/guard.rs#L1-L7); [crates/tui/src/tools/shell.rs:5659-5665](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/shell.rs#L5659-L5665) (verified)
  - *To reach the next level:* The general shell is not replaced by narrow tools and its arguments are not validated beyond the read-only classifier.
- **C L2:** Most built-in tools validate their inputs; MCP and plugin tools are not wrapped by a shared validation layer. — searched `rg -n -i 'sandbox|bwrap|seatbelt'` in `crates/tui/src/mcp/stdio.rs` → 0 hits (MCP stdio servers are launched without any sandbox wrapper); [crates/tui/src/tools/web/guard.rs:1-7](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/web/guard.rs#L1-L7) (verified)
  - *To reach the next level:* No central validation layer that extension tools inherit.
- **D L1:** Work mode ships with shell, write and network tools enabled; shell can be disabled and Plan mode is read-only. — [crates/tui/src/core/authority.rs:404-413](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/core/authority.rs#L404-L413) (verified)
  - *To reach the next level:* Default tool set is not read-only.
- **B L1:** An approved shell command on Linux has the user's full reach; file tools stay in the workspace. — [crates/tui/src/tools/shell.rs:4196-4206](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/shell.rs#L4196-L4206) (verified)
  - *To reach the next level:* Shell reach is not scoped to the project.
- **Cap:** none

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

On Linux, the default scored here, shell commands run as ordinary child processes with no OS sandbox: bubblewrap is used only if you set prefer_bwrap = true, and if bubblewrap is missing it silently runs unsandboxed. When enabled, bubblewrap gives a read-only view of the disk, write access only to the workspace and temp dirs, and no network, and test runners use the same confinement, but MCP servers and language servers still run on the host. On macOS a Seatbelt profile is applied automatically, which would score higher. Without the sandbox, a command reaches your whole home directory.

- **default configuration** (default; raw 0.00 → 0.00)
  - **S L0:** Default Linux execution is a same-user child process with no wrapper. — [crates/tui/src/sandbox/mod.rs:349-362](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/sandbox/mod.rs#L349-L362); [crates/tui/src/sandbox/mod.rs:661-673](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/sandbox/mod.rs#L661-L673) (verified)
    - *To reach the next level:* No OS isolation primitive is applied by default on Linux.
  - **C L0:** No execution path is sandboxed in the default Linux configuration. — [crates/tui/src/tools/shell.rs:4196-4206](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/shell.rs#L4196-L4206) (verified)
    - *To reach the next level:* The main shell tool is not sandboxed by default.
  - **D L0:** Sandboxing on Linux is off unless prefer_bwrap is set. — [crates/tui/src/tui/ui/frame.rs:1029](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tui/ui/frame.rs#L1029); [crates/tui/src/exec_agent.rs:613](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/exec_agent.rs#L613) (verified)
    - *To reach the next level:* Sandbox is opt-in on Linux.
  - **B L0:** Unsandboxed commands reach the user's home directory, including credential files. — [crates/tui/src/tools/shell.rs:4196-4206](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/shell.rs#L4196-L4206); [crates/tui/src/sandbox/read_guard.rs:17-20](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/sandbox/read_guard.rs#L17-L20) (verified)
    - *To reach the next level:* Nothing limits what an executed command can reach on the host.
- **opt-in bubblewrap sandbox (prefer_bwrap = true)** (alt; raw 0.50, cap G1 → 0.50) ← counted
  - **S L3:** bubblewrap with --unshare-all, read-only root bind, writable workspace/temp only, Codewhale state dirs remounted read-only, network namespace isolated by default, no_new_privs on the process. — [crates/tui/src/sandbox/bwrap.rs:126-138](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/sandbox/bwrap.rs#L126-L138); [crates/tui/src/core/authority.rs:329-342](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/core/authority.rs#L329-L342) (verified)
    - *To reach the next level:* No kernel-separated isolation (microVM/gVisor).
  - **C L1:** Shell, gate commands and the test runner use the sandbox; MCP stdio servers and language servers launch on the host. — [crates/tui/src/tools/shell.rs:4196-4206](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/shell.rs#L4196-L4206); searched `rg -n -i 'sandbox|bwrap|seatbelt'` in `crates/tui/src/mcp/stdio.rs` → 0 hits (MCP stdio servers are launched without any sandbox wrapper); [crates/tui/src/lsp/client.rs:196-201](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/lsp/client.rs#L196-L201) (verified)
    - *To reach the next level:* MCP servers and language servers are not wrapped.
  - **D L2:** When opted in, escalation to wider modes is a per-call approval in Ask, but a missing bubblewrap binary silently falls back to host execution. — [crates/tui/src/tools/shell.rs:5343-5347](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/shell.rs#L5343-L5347); [crates/tui/src/sandbox/mod.rs:661-673](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/sandbox/mod.rs#L661-L673) (verified)
    - *To reach the next level:* Silent fallback to unsandboxed execution when bwrap is unavailable.
  - **B L2:** Inside the sandbox the whole disk is readable (a credential deny-list is defense in depth), the workspace is writable and network is off; environment is scrubbed. — [crates/tui/src/sandbox/read_guard.rs:17-20](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/sandbox/read_guard.rs#L17-L20); [crates/tui/src/sandbox/bwrap.rs:126-138](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/sandbox/bwrap.rs#L126-L138) (verified)
    - *To reach the next level:* Mounts are not limited to the workspace and no CPU/memory/PID limits are applied.
- **Cap:** G1 — Opt-in mechanism: off in the scored default configuration.

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

Codewhale does not try to detect prompt injection; its protection is that the things a hijacked agent would need are behind approval. Web fetch, web search and any non-read-only shell command ask you each time, regardless of what the agent has read, so sending data out or running destructive commands needs a person. What a hijacked agent can do unattended is read files (including, on Linux, anything the read-only shell allowlist can reach) and edit project files in a git repository. Tool output is masked for credential-shaped values before reaching the model.

- **S L2:** Egress and shell execution require human approval in every session, but in-workspace file writes do not, and the gate is not tied to whether untrusted content was read. — [crates/tui/src/tools/fetch_url.rs:143-147](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/fetch_url.rs#L143-L147); [crates/tui/src/tools/web_search.rs:306-310](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/web_search.rs#L306-L310); [crates/tui/src/tools/shell.rs:5659-5665](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/shell.rs#L5659-L5665); [crates/tui/src/core/engine/turn_loop.rs:3645-3667](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/core/engine/turn_loop.rs#L3645-L3667) (verified)
  - *To reach the next level:* State-changing workspace writes are not forced through approval once untrusted content is in context.
- **C L2:** The approval requirement applies uniformly to content from files, web, MCP results and sub-agents. — [crates/tui/src/core/authority.rs:456-474](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/core/authority.rs#L456-L474); [crates/tui/src/tui/approval/policy.rs:85](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tui/approval/policy.rs#L85) (verified)
  - *To reach the next level:* Read-only MCP helpers from reviewed plugins auto-run and could act as outbound channels; third-party content is not distinguished from the principal's instructions.
- **D L2:** On by default via the Ask posture; switching to Full Access removes the prompts. — [crates/execpolicy/src/approval_mode.rs:11-16](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/execpolicy/src/approval_mode.rs#L11-L16) (verified)
  - *To reach the next level:* Disabling the gate is a single keypress without a session bound.
- **B L2:** Exfiltration and irreversible actions need a human approval; reversible workspace edits happen unattended. — [crates/tui/src/core/authority.rs:486-495](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/core/authority.rs#L486-L495); [crates/tui/src/tools/fetch_url.rs:143-147](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/fetch_url.rs#L143-L147) (verified)
  - *To reach the next level:* Unattended reads plus unattended workspace writes remain available to a hijacked session.
- **Cap:** none

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

Codewhale is careful with repository-controlled settings: a project's .codewhale/config.toml can only tighten approval, sandbox and shell settings and cannot change endpoints or MCP config, project MCP servers and skills load only after you trust the folder in your own config, and project hooks additionally need a content-hash approval. Long-term memory is off by default and, when on, the model can only propose candidates for you to review. However, AGENTS.md and similar instruction files load silently, and the agent can rewrite them without a prompt in a git repo, so injected instructions can persist into later sessions. A workspace .env is also read at startup, before any trust decision, and can supply model-provider and sandbox-service API keys when you have not configured your own.

- **S L2:** Project config is tighten-only, MCP/hooks/skills need a user-scope trust decision (hooks also a hash receipt), memory writes are review-gated candidates; instruction files load silently. — [crates/tui/src/lib.rs:11900-11912](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/lib.rs#L11900-L11912); [crates/config/src/lib.rs:3843-3852](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/config/src/lib.rs#L3843-L3852); [crates/tui/src/mcp.rs:6303-6309](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/mcp.rs#L6303-L6309); [crates/tui/src/hooks/authority.rs:42-50](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/hooks/authority.rs#L42-L50); [crates/tui/src/project_context.rs:42-48](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/project_context.rs#L42-L48); [crates/tui/src/tools/remember.rs:1-2](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/remember.rs#L1-L2) (verified)
  - *To reach the next level:* Instruction files load without a trust decision and the workspace .env is honored before any trust decision.
- **C L2:** Memory, project config, MCP and hooks are controlled; auto-loaded instruction files and the workspace .env credential loader are not gated. — [crates/tui/src/project_context.rs:42-48](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/project_context.rs#L42-L48); [crates/tui/src/lib.rs:2020](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/lib.rs#L2020); [crates/tui/src/lib.rs:3108-3121](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/lib.rs#L3108-L3121) (verified)
  - *To reach the next level:* Auto-loaded instruction files and workspace .env are outside the trust control.
- **D L3:** Memory is off by default and, when enabled, namespaced per workspace (git origin hash) with model writes limited to review candidates. — [crates/tui/src/config.rs:7658-7671](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/config.rs#L7658-L7671); [crates/tui/src/tools/remember.rs:1-2](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/remember.rs#L1-L2) (verified)
  - *To reach the next level:* No retention limit on by default.
- **B L1:** An injected AGENTS.md persists in the repository across the user's sessions and can steer unattended workspace edits and read-only commands. — [crates/tui/src/project_context.rs:42-48](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/project_context.rs#L42-L48); [crates/tui/src/core/authority.rs:486-495](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/core/authority.rs#L486-L495) (verified)
  - *To reach the next level:* Persisted context can still trigger ungated tool use.
- **Cap:** C6-REPOCONFIG — A workspace .env is loaded at startup without a trust decision and can supply built-in model-provider credentials and the sandbox-service API key (DEEPSEEK_SANDBOX_API_KEY) when the user has not set them.

### C7 Third-party extensions — 0.38 (high)

No third-party code runs by default; the bundled Computer Use plugin is off until reviewed. Plugins get a strong review: each is bound to a hash of its content and declared capabilities, any change forces re-review, and the plugin runtime host runs sandboxed. MCP servers are weaker: servers from your config run whatever command you set, with no pinning or integrity check, and the model can ask to install a server from the public MCP Registry (pinned to a version) or start an arbitrary MCP server command, each behind a per-call approval. MCP servers run as unsandboxed host processes with a scrubbed environment. A trusted project's .codewhale/mcp.json can add servers after the generic folder-trust prompt.

- **S L2:** Registry-installed MCP servers are pinned to a package version and plugins are bound to a content-plus-capability hash receipt; MCP servers from config are launched as configured with no digest check. — [crates/tui/src/tools/mcp_registry.rs:462-467](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/mcp_registry.rs#L462-L467); [crates/tui/src/plugins/types.rs:212-215](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/plugins/types.rs#L212-L215); [crates/tui/src/plugins/types.rs:141](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/plugins/types.rs#L141); searched `rg -n 'sha256|integrity|pinned'` in `crates/tui/src/mcp/stdio.rs` → 0 hits (no version pin or digest check on MCP server launch) (verified)
  - *To reach the next level:* No integrity check or curated allowlist for MCP servers, and no re-approval when an MCP server's tools change.
- **C L1:** Only plugin bundles are hash-verified; MCP servers from user or project config and model-started servers are not. — searched `rg -n 'sha256|integrity|pinned'` in `crates/tui/src/mcp/stdio.rs` → 0 hits (no version pin or digest check on MCP server launch) (verified)
  - *To reach the next level:* MCP servers are not covered by integrity verification.
- **D L1:** Nothing is enabled by default, but the model can request a registry install or an MCP server launch (per-call approval) and trusting a folder (a generic prompt) enables that project's MCP servers. — [crates/tui/src/tools/mcp_registry.rs:993-999](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/mcp_registry.rs#L993-L999); [crates/tui/src/tools/runtime_mcp.rs:216-255](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/runtime_mcp.rs#L216-L255); [crates/tui/src/mcp.rs:6303-6309](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/mcp.rs#L6303-L6309) (verified)
  - *To reach the next level:* Extensions can be added from a model request or a generic folder-trust decision rather than only from user scope with the exact package shown up front.
- **B L2:** MCP servers run as separate processes with a scrubbed, allowlisted environment; the plugin host is sandboxed. — [crates/tui/src/mcp/stdio.rs:169-180](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/mcp/stdio.rs#L169-L180); searched `rg -n -i 'sandbox|bwrap|seatbelt'` in `crates/tui/src/mcp/stdio.rs` → 0 hits (MCP stdio servers are launched without any sandbox wrapper); [crates/tui/src/extension_host/supervisor.rs:7-13](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/extension_host/supervisor.rs#L7-L13) (verified)
  - *To reach the next level:* MCP servers are not sandboxed per extension.
- **Cap:** none

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

Credential-shaped values and configured keys are masked in tool output before it reaches the model and before it is written to saved sessions, and turning that masking off needs a confirmed, receipt-bound opt-out. Child processes never receive secret-shaped environment variables. API keys are stored in a file with owner-only permissions by default (the OS keyring is opt-in). Usage telemetry is on by default and documented as content-free.

- **S L2:** Credential masking before model-bound messages and transcripts, scrubbed child environments; keys stored in a 0600 file by default. — [crates/tui/src/core/engine.rs:4154-4166](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/core/engine.rs#L4154-L4166); [crates/config/src/redaction.rs:1-8](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/config/src/redaction.rs#L1-L8); [crates/secrets/src/lib.rs:4-7](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/secrets/src/lib.rs#L4-L7); [crates/secrets/src/lib.rs:665-673](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/secrets/src/lib.rs#L665-L673) (verified)
  - *To reach the next level:* Stored credentials are not in an OS keychain or encrypted at rest by default.
- **C L3:** Model-bound messages, saved transcripts, subprocess environments and error messages are covered; telemetry is content-free. — [crates/tui/src/core/engine.rs:4154-4166](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/core/engine.rs#L4154-L4166); [crates/tui/src/child_env.rs:100-106](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/child_env.rs#L100-L106); [crates/tui/src/core/engine/turn_loop.rs:94](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/core/engine/turn_loop.rs#L94) (verified)
  - *To reach the next level:* Coverage of every debug and error path is not established.
- **D L1:** Telemetry is on unless the user opts out; it is documented as content-free. — [crates/config/src/lib.rs:3773-3776](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/config/src/lib.rs#L3773-L3776) (verified)
  - *To reach the next level:* Telemetry is not opt-in.
- **B L1:** Provider keys are long-lived and account-scoped; they are kept out of child environments and masked in model-bound output. — [crates/secrets/src/lib.rs:4-7](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/secrets/src/lib.rs#L4-L7) (verified)
  - *To reach the next level:* Keys are not short-lived or rotated by the agent.
- **Cap:** none

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

Each session is saved under ~/.codewhale/sessions with every tool call and result, and a per-session approval receipt log records each approval request and its outcome, including whether a person, a session rule or the posture decided it. These records sit outside the workspace but are ordinary files the agent's own (unsandboxed, on Linux) commands could alter. A separate structured tool-audit log exists only when an environment variable is set. There is no tamper-evidence or off-host export.

- **S L2:** Structured session transcript of every tool call plus approval receipts naming the decider. — [crates/tui/src/approval_log.rs:11-12](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/approval_log.rs#L11-L12); [crates/tui/src/approval_log.rs:43-49](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/approval_log.rs#L43-L49); [crates/tui/src/approval_log.rs:249](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/approval_log.rs#L249) (verified)
  - *To reach the next level:* No correlation IDs or delegation chain across sub-agents verified, and no tamper-evident storage.
- **C L3:** Tool calls including MCP, and approvals and denials, are recorded. — [crates/tui/src/approval_log.rs:43-49](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/approval_log.rs#L43-L49); [crates/tui/src/core/engine/tool_execution.rs:295-301](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/core/engine/tool_execution.rs#L295-L301) (verified)
  - *To reach the next level:* Configuration changes and credential use are not recorded in the same trail.
- **D L2:** On by default and stored outside the workspace, but in a location the agent's commands can reach. — [crates/tui/src/approval_log.rs:249](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/approval_log.rs#L249) (verified)
  - *To reach the next level:* Records are not written by a component the model cannot control.
- **B L2:** Approval receipts are synced to disk per event; audit write failures are logged and the action proceeds. — [crates/tui/src/approval_log.rs:419-424](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/approval_log.rs#L419-L424); [crates/tui/src/audit.rs:16-21](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/audit.rs#L16-L21) (verified)
  - *To reach the next level:* High-risk actions are not blocked when their record cannot be written.
- **Cap:** none

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

By default a turn has no step limit and no wall-clock limit, there is no spend ceiling, and a goal in Operate mode keeps continuing until it is done or you stop it. Individual steps are bounded: shell commands time out after 120 seconds by default, model streams after 30 minutes, and each sub-agent run after 30 minutes, with nesting depth 3 and up to 64 concurrent sub-agents. Pressing Esc cancels the turn and shell commands are killed as a process group. You can configure step and time limits.

- **S L2:** Configurable model-step and turn wall-clock caps plus per-step timeouts enforced in code, and process-group kill on cancel. — [crates/tui/src/core/engine/turn_budget.rs:24-25](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/core/engine/turn_budget.rs#L24-L25); [crates/tui/src/core/engine/turn_budget.rs:32-41](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/core/engine/turn_budget.rs#L32-L41); [crates/tui/src/tools/shell.rs:5217](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/shell.rs#L5217); [crates/tui/src/tools/shell.rs:2417](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/shell.rs#L2417); searched `rg -n 'cost_cap|max_cost|spend_limit|budget_usd'` in `crates/tui/src` → 0 hits (no spend ceiling in the runtime) (verified)
  - *To reach the next level:* No token/cost cap or rate limit on side-effecting tools.
- **C L2:** Top-level loop plus tool timeouts; sub-agents carry their own wall-clock budget, depth and concurrency limits. — [crates/tui/src/tools/subagent/mod.rs:273-277](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/tools/subagent/mod.rs#L273-L277); [crates/config/src/lib.rs:1784](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/config/src/lib.rs#L1784); [crates/tui/src/config/subagent_limits.rs:13](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/config/subagent_limits.rs#L13) (verified)
  - *To reach the next level:* Sub-agents do not count against the parent's budget.
- **D L1:** Step count, turn time and goal continuations are unlimited by default; only per-step timeouts apply. — [crates/tui/src/core/engine/turn_budget.rs:24-25](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/core/engine/turn_budget.rs#L24-L25); [crates/tui/src/core/engine/turn_budget.rs:32-41](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/core/engine/turn_budget.rs#L32-L41); [crates/tui/src/config.rs:7673-7676](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/config.rs#L7673-L7676) (verified)
  - *To reach the next level:* No default ceiling on steps, time or spend.
- **B L1:** A runaway turn can keep calling the model and auto-approved read tools indefinitely; stopping kills running commands. — [crates/tui/src/core/engine/turn_budget.rs:24-25](https://github.com/Hmbown/Codewhale/blob/b131357276568aa969d573129efa0d77c09f68cd/crates/tui/src/core/engine/turn_budget.rs#L24-L25); searched `rg -n 'cost_cap|max_cost|spend_limit|budget_usd'` in `crates/tui/src` → 0 hits (no spend ceiling in the runtime) (verified)
  - *To reach the next level:* No per-run time or cost ceiling.
- **Cap:** none

## Rule-of-Two check
[A] untrusted input: repository files, AGENTS.md (project_context.rs:42-48), web fetch/search results, MCP tool output · [B] sensitive data/systems: files under the user's home readable by auto-approved read-only shell commands (command_safety.rs:394-416) · [C] state change / egress: unprompted in-workspace file writes (authority.rs:486-495); egress and shell need approval (fetch_url.rs:146, shell.rs:5659-5665) · Same default session? Yes

## Highest-impact improvements
1. Use bubblewrap by default on Linux when it is available and refuse (or ask) instead of silently running unsandboxed when it is not. — C4 D L0→L2, +0.100 before caps (Playbook 3 step 2)
2. Ship sensible default ceilings for model steps, turn wall-clock time and goal continuations, and add a spend cap. — C10 D L1→L2, +0.050 before caps (Playbook 3 step 3)
3. Load workspace .env credentials only after an explicit workspace-trust decision, and never the sandbox-service key. — C6 C L2→L3, +0.075 before caps (Playbook 2)
4. Exclude instruction files (AGENTS.md, CLAUDE.md, .agents/) and the legacy .deepseek directory from the unprompted workspace-write carve-out. — C6 B L1→L2, +0.050 before caps (Playbook 2)
5. Make usage telemetry opt-in. — C8 D L1→L2, +0.050 before caps

## Re-audit log
- No changes.

## Limitations
- Static source review of the pinned commit only; nothing was executed, installed, or probed.
- Scored on Linux; on macOS a Seatbelt sandbox is applied automatically, which would raise C4 and several blast-radius ratings. Windows has no OS sandbox.
- Headless `codewhale exec`, the local web client, the runtime API, the ACP server, Fleet workers and the Auto-Review model guardian were examined only where they share the interactive engine's gates.
- The tui crate is about 1.18M lines; the review focused on tool registration, the approval resolver, the sandbox, child environment, config precedence, MCP/plugin loading and session storage.
- Language-server integration is off on a fresh install (no [lsp] table); when enabled, language servers spawn on the host and can execute workspace build scripts without approval.
- No text aimed at steering AI reviewers was found in the files read.
