# Ablation Evidence: seatbelt-run vs the deprecated sandbox-exec CLI Date: 2026-08-17 · Host: macOS arm64 (Darwin) · dsh v0.1.0-rc.6 · dsh-seatbelt-sandbox @ master ## Goal Prove two properties of the plugin against the deprecated `sandbox-exec` CLI: 1. **Decoupling** — the plugin's seatbelt capability does not depend on the deprecated CLI at all (it loads `libsandbox` directly through the `seatbelt-run` loader, resolved by absolute path). 2. **Fail-closed preservation** — replacing the official rung must not weaken dsh's safety semantics: when no backend is usable, dsh must refuse to run commands unconfined (exactly like the official rung). ## Method: PATH-shadowing an "archived" sandbox-exec `/usr/bin/sandbox-exec` is SIP-protected (`restricted` flag; writes to `/usr/bin` fail with `Operation not permitted` even as root), so physical archival is impossible. Instead we shadow it on `PATH`: - A shim at `/ablation/bin/sandbox-exec` prints `sandbox-exec: archived (ablation shadow, exit 125)` and exits 125. - The official `@deepseek-ai/dsh-sandbox-local` resolves the **bare name** `sandbox-exec` via PATH (`seatbeltExec() ?? "sandbox-exec"`, confirmed in `dsh-sandbox-local/lib/index.js`), so the shim is hit whenever the official rung probes or confines. - The plugin resolves `seatbelt-run` by **absolute path** under `bin/darwin-/`, so the shadow cannot affect it. Simulation command: `PATH=/ablation/bin:$PATH dsh web` ## Evidence ### Phase A — baseline (plugin installed, normal PATH) `examples/verify-dsh-boot.mjs`: **8/8 pass** (provider identity, argv shape `[seatbelt-run, profile, --, ...argv]`, no `sandbox-exec`, kernel denial, workspace-write, consumer attribution). ### Phase B — plugin installed + sandbox-exec shadowed Same script under `PATH=/ablation/bin:$PATH`: **8/8 pass**. The plugin's full capability is unaffected by the missing CLI. ### Phase C — official rung (plugin removed) + sandbox-exec shadowed Boot reaches the official `LocalSandboxProvider`; probe hits the shim; the consumer refuses to run any command: ``` SandboxUnavailableError: sandbox mode "read-only" is requested but no sandbox backend is usable on this host; refusing to run the command unconfined. Install bubblewrap or run a Landlock-enforcing kernel (Linux), ensure sandbox-exec is usable (macOS), or ensure the ACL restricted-token runner can start (Windows) — otherwise switch the consumer to danger-full-access. Runner failure: sandbox-exec: archived (ablation shadow, exit 125) code: 'SANDBOX_UNAVAILABLE' ``` ### Phase C' — official rung + normal PATH (control) Sandbox works again (real `sandbox-exec`), but argv[0] is `sandbox-exec` and the provider is `LocalSandboxProvider` — i.e. the old implementation. ### Manual two-stage ablation (run by the user in the live harness) | Stage | Setup | Observed in harness session | |---|---|---| | 1 | plugin removed + PATH shadow; restart `dsh web` with shadowed PATH | **Every command refused**: `uname -s -m` fails with `SandboxUnavailableError`, `Runner failure: sandbox-exec: archived (ablation shadow, exit 125)` | | 2 | plugin reinstalled + same PATH shadow; restart | **All normal**: `uname` OK; workspace-in write OK; workspace-out write denied by the kernel with `Operation not permitted` (file not created); /tmp write OK; read-only OK; no `sandbox-exec` trace | ## Reproduce ```sh # Setup mkdir -p ~/Desktop/dsh/ablation/bin cat > ~/Desktop/dsh/ablation/bin/sandbox-exec <<'EOF' #!/bin/sh echo "sandbox-exec: archived (ablation shadow, exit 125)" >&2 exit 125 EOF chmod +x ~/Desktop/dsh/ablation/bin/sandbox-exec # Stage 1 (expect fail-closed errors) dsh plugin --profile web remove dsh-seatbelt-sandbox kill $(lsof -tnP -iTCP:3080 -sTCP:LISTEN) cd PATH=$HOME/Desktop/dsh/ablation/bin:$PATH dsh web # → in the harness: any sandboxed command fails with SANDBOX_UNAVAILABLE # Stage 2 (expect normal operation) dsh plugin --profile web add kill $(lsof -tnP -iTCP:3080 -sTCP:LISTEN) cd PATH=$HOME/Desktop/dsh/ablation/bin:$PATH dsh web # → in the harness: commands run; outside-write denied with # "Operation not permitted" (kernel), not a backend error # Restore clean state kill $(lsof -tnP -iTCP:3080 -sTCP:LISTEN) cd dsh web # normal PATH ``` ## Conclusion - The plugin's capability is **fully decoupled** from the deprecated `sandbox-exec` CLI (absolute-path `seatbelt-run` → `libsandbox`). - Replacing the official rung **preserves fail-closed semantics**: with the CLI missing, the official rung refuses everything (`SANDBOX_UNAVAILABLE`), while the plugin keeps enforcing the same kernel-level policy (`Operation not permitted`, temp-area grants, consumer attribution). - Switching engines changes the launch channel only; the enforcement authority remains the macOS kernel seatbelt, and the denial dialect (`operation not permitted`) is unchanged, so `ctx.shell` attribution (`denied=true`) is preserved.