Skip to content

sandbox/macos: add deny-first rules for well-known secret paths #3086

@bug-ops

Description

@bug-ops

Description

PR #3085 fixed #3077 by replacing per-path (allow file-read* (subpath ...)) rules with a global (allow file-read*) in the Seatbelt workspace profile. This is necessary to load dylibs from the macOS DYLD shared cache, but it also makes credential files readable by sandboxed bash (e.g. cat ~/.ssh/id_rsa would succeed).

The FirewallVerifier at crates/zeph-tools/src/verifier.rs:824-838 partially mitigates this for literal path references in bash commands, but does not catch wildcard/indirect access (tar, find, cp).

The fix is to add deny-first subpath rules for well-known secret paths before the global (allow file-read*) rule. In Seatbelt, the last matching rule wins — so (deny file-read*) placed after the global allow would take precedence.

Expected Behavior

Sandboxed bash should not be able to read files in known credential locations even under the workspace profile.

Affected File

crates/zeph-tools/src/sandbox/macos.rsgenerate_sb_profile(), workspace profile branch.

Deny list (minimum)

(deny file-read* (subpath (string-append (param "HOME") "/.ssh")))
(deny file-read* (subpath (string-append (param "HOME") "/.aws")))
(deny file-read* (subpath (string-append (param "HOME") "/.config/gh")))
(deny file-read* (subpath (string-append (param "HOME") "/.config/op")))
(deny file-read* (subpath (string-append (param "HOME") "/.config/gcloud")))
(deny file-read* (subpath (string-append (param "HOME") "/.azure")))
(deny file-read* (subpath (string-append (param "HOME") "/.netrc")))
(deny file-read* (subpath (string-append (param "HOME") "/.docker/config.json")))
(deny file-read* (subpath (string-append (param "HOME") "/.kube/config")))
(deny file-read* (subpath (string-append (param "HOME") "/.gnupg")))
(deny file-read* (subpath (string-append (param "HOME") "/.password-store")))
(deny file-read* (subpath (string-append (param "HOME") "/.cargo/credentials.toml")))
(deny file-read* (subpath (string-append (param "HOME") "/.npmrc")))
(deny file-read* (subpath (string-append (param "HOME") "/.zsh_history")))
(deny file-read* (subpath (string-append (param "HOME") "/.bash_history")))
(deny file-read* (subpath (string-append (param "HOME") "/Library/Keychains")))
(deny file-read* (subpath (string-append (param "HOME") "/Library/Cookies")))

Compensating control (existing)

FirewallVerifier already blocks literal references to ~/.ssh/*, ~/.aws/*, *.pem, id_rsa, credentials etc. at pre-execution. Does not cover indirect access.

Acceptance Criteria

  • sandbox-exec -f <workspace.sb> /bin/bash -c "cat ~/.ssh/id_rsa" → denied
  • sandbox-exec -f <workspace.sb> /bin/bash -c "echo hello" → still works
  • sandbox-exec -f <workspace.sb> /bin/bash -c "ls ~" → still works (home listing OK)
  • Deny list documented in specs/010-security/spec.md

Metadata

Metadata

Assignees

Labels

P1High ROI, low complexity — do next sprintbugSomething isn't workingsecuritySecurity-related issue

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions