Skip to content

harden(sandbox): H2 follow-ups — untrusted defaults, exec confinement, pin propagation - #362

Merged
oratis merged 1 commit into
mainfrom
claude/h2-followup
Aug 14, 2026
Merged

harden(sandbox): H2 follow-ups — untrusted defaults, exec confinement, pin propagation#362
oratis merged 1 commit into
mainfrom
claude/h2-followup

Conversation

@oratis

@oratis oratis commented Aug 14, 2026

Copy link
Copy Markdown
Owner

Closes the three follow-ups flagged when H2 (#359) merged (its comment lists them). H2's core — a pinned mode actually enforcing — is already in main; this finishes the coverage. typecheck clean; full suite green (the one failing test is the known moodBus parallelism flake, passes in isolation).

HIGH-2 — untrusted/unattended surfaces no longer inherit danger-full-access

channels (remote DMs), idle, and heartbeat now default to untrustedSurfaceMode():

  • Enforceable host (macOS Seatbelt / Linux + bwrap): capped at workspace-write, honouring a stricter env pin (read-only).
  • No OS sandbox: bounded modes fail closed and would silently break autonomy, so it keeps the env default and warns once — a loud "install bwrap" beats a broken heartbeat. An operator forces fail-closed everywhere with LISA_SANDBOX_MODE.

(idle already runs a no-fs/shell subset and the mail/KB classifiers pass tools: [], so this is defense-in-depth there and load-bearing for heartbeat full-tool turns + unsafeFullTools channels.)

MED-3 — shell.exec now confined

exec (argv form) routes through the new wrapArgvForSandbox — the same fail-closed path as run, sharing one core (wrapProgram). Previously grep/exec ran unconfined even under read-only/workspace-write; now one mode governs both shell halves.

Pin propagation (completes HIGH-1 coverage)

  • Web turn threads chat.session.header.sandboxMode, so concurrent web sessions confine independently of the process env.
  • task (dispatched subagent) inherits ctx.sandboxMode — a subagent can't escape its caller's confinement.

Tests

Host-independent: untrusted-surface capping, argv pass-through when unconfined, and confine/fail-closed of a bounded argv.

🤖 Generated with Claude Code

…finement, pin propagation

Closes the follow-ups flagged when H2 (#359) merged:

- HIGH-2: untrusted/unattended surfaces (channels, idle, heartbeat) now default
  to a confined `untrustedSurfaceMode()` instead of inheriting the local user's
  `danger-full-access` — capped at workspace-write where the host can enforce it
  (macOS Seatbelt / Linux bwrap), honouring a stricter env pin. Where no OS
  sandbox exists, bounded modes would fail closed and silently break autonomy,
  so it keeps the env default and warns once (loud "install bwrap" > broken
  heartbeat); an operator can force fail-closed everywhere with LISA_SANDBOX_MODE.
- MED-3: `shell.exec` (argv form) now routes through `wrapArgvForSandbox`, the
  same fail-closed confinement as `run` — so ONE mode governs both shell halves.
  Previously grep/exec ran unconfined even under read-only/workspace-write.
- Pin propagation: the web turn threads `chat.session.header.sandboxMode`
  (concurrent web sessions confine independently), and `task` (dispatched
  subagent) inherits `ctx.sandboxMode` so it can't escape its caller's sandbox.

Tests: untrusted-surface mode capping (host-independent), argv pass-through when
unconfined, and fail-closed/confine of a bounded argv.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@oratis
oratis merged commit 256dcdc into main Aug 14, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant