diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md
index 3e988d9..5c10d9b 100644
--- a/.planning/ROADMAP.md
+++ b/.planning/ROADMAP.md
@@ -37,7 +37,10 @@ Full details: [milestones/v1.0-ROADMAP.md](milestones/v1.0-ROADMAP.md)
1. Running claudebox with an active Claude subscription succeeds without re-authentication
2. OAuth token refresh completes silently — credentials file is updated and the session continues
3. When `ANTHROPIC_API_KEY` is set on the host, it is passed into the sandbox and takes precedence over OAuth
-**Plans**: TBD
+**Plans**: 1 plan
+
+Plans:
+- [ ] 04-01-PLAN.md — Credential mount + audit redesign (unified env list, Mounts section, Network section)
### Phase 5: Per-Project Instance Isolation
**Goal**: Each project directory has its own isolated Claude state so conversation history, todos, and settings do not bleed between projects
@@ -81,7 +84,7 @@ Full details: [milestones/v1.0-ROADMAP.md](milestones/v1.0-ROADMAP.md)
| 1. Minimal Viable Sandbox | v1.0 | 2/2 | Complete | 2026-04-09 |
| 2. Env Audit and CLI Polish | v1.0 | 2/2 | Complete | 2026-04-09 |
| 3. Sandbox-Aware Prompting | v1.0 | 1/1 | Complete | 2026-04-10 |
-| 4. Auth Passthrough | v2.0 | 0/? | Not started | - |
+| 4. Auth Passthrough | v2.0 | 0/1 | Not started | - |
| 5. Per-Project Instance Isolation | v2.0 | 0/? | Not started | - |
| 6. Tiered Network Isolation | v2.0 | 0/? | Not started | - |
| 7. Named Profiles | v2.0 | 0/? | Not started | - |
diff --git a/.planning/phases/04-auth-passthrough/04-01-PLAN.md b/.planning/phases/04-auth-passthrough/04-01-PLAN.md
new file mode 100644
index 0000000..549b98d
--- /dev/null
+++ b/.planning/phases/04-auth-passthrough/04-01-PLAN.md
@@ -0,0 +1,211 @@
+---
+plan: 1
+phase: 04
+wave: 1
+depends_on: []
+files_modified:
+ - claudebox.sh
+requirements: [AUTH-01, AUTH-02]
+autonomous: true
+must_haves:
+ truths:
+ - "claudebox launches successfully when ~/.claude/.credentials.json exists on the host"
+ - "OAuth token refresh can write back to the credentials file (read-write mount)"
+ - "claudebox launches without error when ~/.claude/.credentials.json does not exist"
+ - "ANTHROPIC_API_KEY is passed into the sandbox when set on the host"
+ - "The audit screen shows all env vars in a single unified list with [~]/[>]/[+] prefixes"
+ - "The audit screen shows a Mounts section and a Network section after the env list"
+ - "The --dry-run output mirrors the credential bind when the file exists"
+ artifacts:
+ - path: "claudebox.sh"
+ provides: "Credential mount logic, updated print_audit, updated --dry-run block"
+ contains: "credentials.json"
+ key_links:
+ - from: "claudebox.sh credential bind block"
+ to: "exec bwrap call (line ~327)"
+ via: "--bind $HOME/.claude/.credentials.json $HOME/.claude/.credentials.json"
+ - from: "claudebox.sh credential bind block"
+ to: "--dry-run display block (line ~292)"
+ via: "mirrored echo of credential bind"
+ - from: "print_audit"
+ to: "AUDIT_SANDBOX_KEYS / AUDIT_HOST_KEYS / AUDIT_EXTRA_KEYS arrays"
+ via: "[~]/[>]/[+] prefix loop"
+---
+
+# Plan 1: Credential Mount + Audit Redesign
+
+## Goal
+
+Mount `~/.claude/.credentials.json` read-write into the sandbox and rewrite the pre-launch audit to a unified env/mounts/network display.
+
+## Context
+
+Claude Code stores OAuth tokens in `~/.claude/.credentials.json`. Without mounting this file, users must re-authenticate every time. The mount must be read-write because OAuth refresh writes new tokens back to the file. When `ANTHROPIC_API_KEY` is set on the host, it is already passed through (line 204 of claudebox.sh) — no changes needed for that path.
+
+The current audit shows three separate sections (Sandbox-generated / Host allowlisted / Extra). The redesign collapses these into one list with `[~]`/`[>]`/`[+]` prefixes (accessible without color), adds a Mounts section showing active filesystem binds, and adds a Network section (placeholder showing "full (host network)" until Phase 6).
+
+
+## Threat Model
+
+**Assets:**
+- `~/.claude/.credentials.json` — OAuth tokens granting access to the user's Claude subscription
+- `ANTHROPIC_API_KEY` — API key granting billable Claude API access
+
+**Threat actors:**
+- Malicious code running inside the sandbox that could exfiltrate credentials via network or file writes
+- A compromised Claude Code session writing a crafted `.credentials.json` back to the host
+
+**Attack vectors:**
+- Sandbox code reads `.credentials.json` and exfiltrates tokens over the network (full host network in Phase 4)
+- Sandbox code overwrites `.credentials.json` with attacker-controlled content, poisoning the host credential store
+- Path traversal: if the bind target were `$HOME/.claude/` (directory), sandbox code could write new files into `~/.claude` on the host
+
+**Mitigations:**
+- Bind is file-scoped (`--bind .credentials.json .credentials.json`), NOT directory-scoped — sandbox cannot create new files in the host `~/.claude` directory via this mount
+- Read-write is required for legitimate OAuth refresh; this is an accepted trade-off documented in D-02
+- `ANTHROPIC_API_KEY` is masked in audit output by `mask_value` (already implemented)
+- Phase 6 network isolation will allow users to restrict exfiltration surface; Phase 4 accepts full-network risk consistent with existing behavior
+
+**Residual risk:**
+- A malicious prompt could cause Claude to read and exfiltrate the OAuth token over the network. Accepted: this is equivalent risk to the API key already in the sandbox. Phase 6 network tiers reduce this surface.
+- OAuth token can be overwritten by sandbox code. Accepted: the file must be writable for refresh to work (D-02). The host file is the user's own credential file.
+
+
+## Tasks
+
+
+
+
+- claudebox.sh lines 284–350 — the --dry-run display block and exec bwrap call; credential bind goes in both places
+- claudebox.sh lines 98–103 — CWD and ~/.claudebox setup pattern to follow
+
+
+After the `mkdir -p "$HOME/.claudebox"` call and before the `print_audit` invocation, add a block that:
+
+1. Sets `CREDS_FILE="$HOME/.claude/.credentials.json"`
+2. Checks `if [[ -f "$CREDS_FILE" ]]; then` sets `CREDS_MOUNT=true`; else `CREDS_MOUNT=false`
+3. Adds `--bind "$CREDS_FILE" "$HOME/.claude/.credentials.json"` to the exec bwrap call (after the `--symlink "$HOME/.claudebox" "$HOME/.claude"` line) when `CREDS_MOUNT=true`
+4. Mirrors the same conditional bind in the `--dry-run` display block (after the symlink echo)
+
+**Bwrap mount ordering note:** The credential file bind must come AFTER the `--symlink "$HOME/.claudebox" "$HOME/.claude"` line. bwrap processes mounts in order; the symlink creates `~/.claude → ~/.claudebox`, and the subsequent file bind layers `.credentials.json` on top of it inside the sandbox. This matches the established pattern from the code context.
+
+Do NOT use `--ro-bind` — the mount must be read-write for OAuth token refresh (D-02).
+
+Do NOT add any warning or error output when the file is absent — skip silently (D-03).
+
+Always add the bind when the file exists, even if `ANTHROPIC_API_KEY` is also set (D-04).
+
+
+- [ ] `grep -n 'CREDS_FILE' claudebox.sh` shows the variable declared as `CREDS_FILE="$HOME/.claude/.credentials.json"`
+- [ ] `grep -n 'CREDS_MOUNT' claudebox.sh` shows both the conditional set and usage in bwrap exec
+- [ ] `grep -n 'credentials.json' claudebox.sh` shows the bind appears in BOTH the exec bwrap block AND the --dry-run block
+- [ ] The bind uses `--bind` (not `--ro-bind`) — `grep 'ro-bind.*credentials' claudebox.sh` returns nothing
+- [ ] `grep -A2 'CREDS_MOUNT' claudebox.sh` shows the condition is `[[ -f "$CREDS_FILE" ]]` — file existence check, not variable existence
+- [ ] No `echo` or `>&2` output is produced when the credentials file is absent — the skip is completely silent
+
+
+
+
+
+
+
+- claudebox.sh lines 171–263 — the audit data structures (AUDIT_SANDBOX_KEYS, AUDIT_HOST_KEYS, AUDIT_EXTRA_KEYS arrays and associated maps) and the current print_audit function; the rewrite must consume the same data structures
+- claudebox.sh lines 65–76 — ANSI color variable definitions (BOLD, RESET, DIM, CYAN, YELLOW, GREEN, RED already defined)
+- claudebox.sh lines 78–91 — mask_value function signature and behavior; must be called for all env var values in the new display
+
+
+Rewrite the `print_audit` function (lines 227–263) to produce the new unified format per D-06, D-07, D-08, D-09, D-10.
+
+**New print_audit structure:**
+
+```
+=== Sandbox Environment ===
+
+ [~] HOME=/home/user ← green [~] prefix, sandbox-generated
+ [~] USER=user
+ [~] PATH= ← PATH gets special multiline treatment (same as before)
+ /nix/store/.../bin
+ [>] TERM=xterm-256color ← yellow [>] prefix, host allowlisted (only if set)
+ [>] ANTHROPIC_API_KEY=abc123...xyz ← masked by mask_value
+ [+] MY_VAR=value ← cyan [+] prefix, extra via CLAUDEBOX_EXTRA_ENV
+
+Mounts:
+ CWD /path/to/project (read-write)
+ ~/.claude ~/.claudebox (read-write)
+ credentials ~/.claude/.credentials.json (read-write) ← only if CREDS_MOUNT=true
+
+Network:
+ full (host network)
+```
+
+**Implementation rules:**
+
+1. Single loop over all three key arrays in order: sandbox keys first ([~]), then host keys ([>]), then extra keys ([+])
+2. Each line: ` {COLOR}{PREFIX}{RESET} {var}={masked_value}` — the prefix `[~]`, `[>]`, `[+]` is printed in color AND must be readable without color (accessibility per D-07)
+3. PATH gets the same multiline indented treatment as the current implementation — show label then each path entry indented
+4. After the env list, print a blank line then `${BOLD}Mounts:${RESET}` section:
+ - Always show: ` CWD $CWD (read-write)`
+ - Always show: ` ~/.claude $HOME/.claudebox (read-write)`
+ - Conditionally show (when `CREDS_MOUNT=true`): ` credentials $HOME/.claude/.credentials.json (read-write)`
+ - Use consistent column alignment — pad the label to a fixed width (e.g., 12 chars) so values align
+5. After Mounts, print a blank line then `${BOLD}Network:${RESET}` section:
+ - Always show: ` full (host network)`
+ - This is a Phase 4 placeholder — no dynamic logic
+6. All output to stderr (`>&2`)
+7. Unset allowlisted host vars are silently omitted from the display (discretion decision from CONTEXT.md)
+
+The existing `AUDIT_SANDBOX_KEYS`, `AUDIT_SANDBOX_VALS`, `AUDIT_HOST_KEYS`, `AUDIT_HOST_VALS`, `AUDIT_EXTRA_KEYS`, `AUDIT_EXTRA_VALS` arrays must NOT be restructured — only `print_audit` changes.
+
+
+- [ ] `grep '\[~\]' claudebox.sh` matches inside print_audit, used for sandbox-generated vars
+- [ ] `grep '\[>\]' claudebox.sh` matches inside print_audit, used for host-allowlisted vars
+- [ ] `grep '\[+\]' claudebox.sh` matches inside print_audit, used for extra vars
+- [ ] `grep 'Mounts:' claudebox.sh` matches inside print_audit
+- [ ] `grep 'Network:' claudebox.sh` matches inside print_audit
+- [ ] `grep 'full (host network)' claudebox.sh` matches inside print_audit
+- [ ] `grep 'CREDS_MOUNT' claudebox.sh` shows the Mounts section conditionally includes the credentials line
+- [ ] `grep 'mask_value' claudebox.sh` shows mask_value is called for every env var value in the new loops (not just some vars)
+- [ ] `grep '>&2' claudebox.sh` — all print_audit echo/printf calls redirect to stderr
+- [ ] `bash -n claudebox.sh` exits 0 (no syntax errors)
+
+
+
+
+## Verification
+
+```bash
+# Syntax check
+bash -n claudebox.sh
+
+# Verify credential bind present in both exec and dry-run blocks
+grep -n 'credentials.json' claudebox.sh
+
+# Verify read-write (not ro-bind) for credentials
+grep 'ro-bind.*credentials' claudebox.sh # must return nothing
+
+# Verify prefix scheme present
+grep -E '\[~\]|\[>\]|\[+\]' claudebox.sh
+
+# Verify Mounts and Network sections
+grep -E 'Mounts:|Network:|full .host network.' claudebox.sh
+
+# Functional test: dry-run with credentials file present
+# (Create a test file, run dry-run, confirm bind appears in output)
+touch /tmp/test_credentials.json
+HOME_ORIG="$HOME"
+# If test harness available: claudebox --dry-run should show --bind ...credentials.json
+```
+
+## Must-Haves
+
+- `~/.claude/.credentials.json` is mounted read-write into the sandbox when it exists on the host
+- When the file does not exist, claudebox starts without any error or warning
+- The exec bwrap call and the --dry-run display block are in sync (credential bind appears in both or neither)
+- The audit screen shows `[~]`, `[>]`, and `[+]` prefixes that distinguish env var categories without relying on color alone
+- The audit screen shows a Mounts section listing CWD, ~/.claude, and (conditionally) the credentials file
+- The audit screen shows a Network section with "full (host network)" as a Phase 6 placeholder
+- `bash -n claudebox.sh` passes (no syntax errors introduced)
+
+## Output
+
+After completion, create `.planning/phases/04-auth-passthrough/04-01-SUMMARY.md`