Skip to content

fix: restrict macOS sandbox file read access#4

Open
cbarber wants to merge 10 commits intomainfrom
fix/macos-sandbox-security
Open

fix: restrict macOS sandbox file read access#4
cbarber wants to merge 10 commits intomainfrom
fix/macos-sandbox-security

Conversation

@cbarber
Copy link
Owner

@cbarber cbarber commented Dec 30, 2025

Summary

  • Replace global file-read* with explicit path whitelisting in macOS sandbox
  • Match Linux bubblewrap security model: only allow reads of necessary paths
  • Block agent access to personal SSH keys, API tokens, and sensitive files
  • Add CI tests to verify sensitive file access is blocked
  • Document security model and design rationale in SANDBOX.md

Context

The macOS sandbox profile was copied from OpenAI Codex which uses:

(allow file-read*)  ;; Global read access - SECURITY THEATER!

This allowed agents to read any file on the system, including:

  • Personal SSH keys (~/.ssh/id_rsa)
  • GitHub CLI tokens (~/.config/gh/hosts.yml)
  • AWS credentials (~/.aws/credentials)
  • Browser session data and personal documents

While write restrictions prevented damage, agents could exfiltrate sensitive data. This made the sandbox security theater.

Changes

Replace with explicit whitelisting matching Linux bubblewrap:

Allowed read access:

  • System paths: Nix store, libraries, DNS, SSL certs
  • Project directory (current working dir only)
  • Agent configs: ~/.claude, ~/.config/opencode, caches
  • Agent SSH keys: ~/.ssh/agent-* (NOT personal keys)

Blocked access:

  • Personal SSH keys (~/.ssh/id_rsa, etc.)
  • Personal configs (~/.config/gh, ~/.aws, etc.)
  • Documents, Downloads, Desktop
  • All other personal files

Testing

CI tests verify:

  • Agents cannot read personal SSH keys
  • Agents cannot read GitHub CLI credentials
  • Agents can still access project files and agent configs
  • Network operations work (Nix, API calls)

Resolves llm-tools-b2z (P0 security issue)


🤖 Created by agent


🤖 Created by agent

claude added 10 commits January 6, 2026 12:48
macOS sandbox used global (allow file-read*) copied from Codex, allowing
agents to read API keys, SSH keys, personal documents, and browser data.
This made sandbox security theater - write restrictions prevented damage
but agents could exfiltrate sensitive data.

Replace with explicit path whitelisting matching Linux bubblewrap:
- System paths: Nix store, libraries, DNS, SSL certs
- Project directory: current working directory only
- Agent configs: ~/.claude, ~/.config/opencode, caches
- Agent SSH keys: ~/.ssh/agent-* only (not personal keys)

Block access to:
- Personal SSH keys (~/.ssh/id_rsa)
- Personal configs (~/.config/gh, ~/.aws)
- Documents, Downloads, Desktop
- All other personal files

Add CI tests to verify sensitive files are blocked. Update SANDBOX.md
with security model comparison and design rationale.

Authored By: OpenCode (claude-sonnet-4-20250514)
Add 'forge pr checks NUMBER' to view CI status for PRs.
Add 'forge pr logs RUN_ID' to fetch workflow run logs.

Run ID is obtained from checks output. Resolves llm-tools-zwk.

Authored By: OpenCode (claude-sonnet-4-20250514)
Add 4 experiments to CI (all continue-on-error):
1. Test if (subpath ...) on non-existent directory causes abort
2. Use dtruss to trace file access during sandbox-exec
3. Use fs_usage to see filesystem activity
4. Test minimal known-good profile

This will help identify the actual cause of exit code 134 (SIGABRT).
Experiments can be removed once root cause is found.

Authored By: OpenCode (claude-sonnet-4-20250514)
Experiment 4 failed even with minimal profile. Need to check:
- Does /nix exist on macOS runner?
- Does removing /nix reference fix the abort?

Authored By: OpenCode (claude-sonnet-4-20250514)
Even minimal profiles with just /bin and /usr are aborting.
Test with process-fork, signal, sysctl-read, and global file-read
to see if more permissions fix the abort.

Authored By: OpenCode (claude-sonnet-4-20250514)
Experiments show sandbox-exec aborts with exit 134 when signal
operations are restricted to same-sandbox only. Change from:
  (allow signal (target same-sandbox))
to:
  (allow signal)

This matches the working profile from experiment 7.

Authored By: OpenCode (claude-sonnet-4-20250514)
macOS system files live in /var and /private/var. sandbox-exec
likely needs to read system files during initialization.

Adding these paths to whitelist to fix abort.

Authored By: OpenCode (claude-sonnet-4-20250514)
sandbox-exec aborts (exit 134) when (literal ...) references non-existent
files. Move HOME_CLAUDE_JSON and SSH key paths to conditional handling -
only add to profile if files actually exist on the system.
This prevents abort on CI runners and fresh systems where these files
may not exist yet.
@cbarber cbarber force-pushed the fix/macos-sandbox-security branch from e6573fd to 021e71b Compare January 6, 2026 17:50
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.

2 participants

Comments