macOS Sandbox Security
A comprehensive guide to understanding, working with, and debugging macOS Sandbox security mechanisms.
What is macOS Sandbox?
macOS Sandbox (originally called Seatbelt) limits applications to only the allowed actions specified in their Sandbox profile. This ensures applications access only expected resources.
Key facts:
- Any app with entitlement
com.apple.security.app-sandboxruns inside the sandbox - All App Store apps have this entitlement
- Apple binaries are usually sandboxed
- Uses MACF (Mandatory Access Control Framework) hooks for most syscalls
Core Components
| Component | Path | Purpose |
|---|---|---|
| Kernel Extension | /System/Library/Extensions/Sandbox.kext |
Core sandbox enforcement |
| Private Framework | /System/Library/PrivateFrameworks/AppSandbox.framework |
Sandbox APIs |
| Daemon | /usr/libexec/sandboxd |
Userland sandbox manager |
| Containers | ~/Library/Containers |
App-specific isolated directories |
Understanding Containers
Every sandboxed application has its own container:
# List all containers
ls -l ~/Library/Containers
# Inspect a specific container
cd ~/Library/Containers/{CFBundleIdentifier}
ls -la
Container structure:
.com.apple.containermanagerd.metadata.plist- Container configurationData/- App data directory (mimics home folder structure)
Important: Even with symlinks to Desktop, Downloads, etc., the app needs explicit permissions in the .plist file's RedirectablePaths to access them.
Sandbox Profiles (SBPL)
Sandbox profiles use Sandbox Profile Language (SBPL), based on Scheme:
(version 1) ; Profile version
(deny default) ; Default action when no rule matches
(allow network*) ; Allow all network operations
(allow file-read* ; Allow file reads from:
(subpath "/Users/username/")
(literal "/tmp/afile")
(regex #"^/private/etc/.*")
)
(allow mach-lookup ; Allow specific Mach port
(global-name "com.apple.analyticsd")
)
Common operations:
file*- All file operationsfile-read*- File read operationsfile-write*- File write operationsprocess*- Process executionnetwork*- Network operationsmach-lookup- Mach port access
Creating and Testing Sandbox Profiles
Basic Profile Creation
# Create a profile file
cat > /tmp/test.sb << 'EOF'
(version 1)
(deny default)
(allow file* (literal "/tmp/test.txt"))
(allow process* (literal "/usr/bin/touch"))
(allow file-read-data (literal "/"))
EOF
# Run command with profile
sandbox-exec -f /tmp/test.sb /usr/bin/touch /tmp/test.txt
Common Profile Patterns
Minimal network access:
(version 1)
(deny default)
(allow network-client-connect)
(allow file-read* (subpath "~/"))
File server (read-only):
(version 1)
(deny default)
(allow network-server)
(allow file-read* (subpath "/var/www/"))
Development with temp access:
(version 1)
(deny default)
(allow file* (subpath "/tmp/"))
(allow file* (subpath "~/Downloads/"))
(allow process-exec (subpath "/usr/bin/"))
Inspecting Sandboxed Processes
Using sbtool
# Check if PID can access a file
sbtool <pid> file /tmp
# Check Mach port access
sbtool <pid> mach
# Full inspection of sandbox state
sbtool <pid> inspect
# Check all permissions
sbtool <pid> all
Using log show
# View recent sandbox denials
log show --style syslog --predicate 'eventMessage contains[c] "sandbox"' --last 30s
# Filter for specific process
log show --predicate 'processImagePath contains "AppName" and eventMessage contains "sandbox"' --last 1h
Container Configuration
# Get container metadata (requires FDA)
plutil -convert xml1 ~/Library/Containers/{bundle-id}/.com.apple.containermanagerd.metadata.plist -o -
# Look for:
# - SandboxProfileData (compiled profile)
# - Entitlements (granted permissions)
# - RedirectablePaths (accessible paths)
Sandbox Tracing
Via Profile
# Create trace profile
cat > /tmp/trace.sb << 'EOF'
(version 1)
(trace /tmp/trace.out)
EOF
# Run with tracing
sandbox-exec -f /tmp/trace.sb /bin/ls
# View trace output
cat /tmp/trace.out
Via Command Line
# Inline trace
sandbox-exec -t /tmp/trace.out -p "(version 1)" /bin/ls
System Sandbox Profiles
Locations:
/usr/share/sandbox/- System profiles/System/Library/Sandbox/Profiles/- Application profiles/System/Library/Sandbox/rootless.conf- SIP platform profile
Common profiles:
application.sb- Default App Store app profileplatform.sb- Platform policy (SIP)*.sb- Various system daemon profiles
Sandbox Extensions
Extensions grant additional privileges to sandboxed processes:
Extension types:
sandbox_extension_issue_file- File accesssandbox_extension_issue_mach- Mach port accesssandbox_extension_issue_iokit_user_client_class- I/O Kit accesssandbox_extension_issue_generic- Generic extension
Key points:
- Extensions are usually granted by allowed processes (e.g.,
tccdfor photos) - Extension tokens are long hex strings encoding permissions
- Tokens can be consumed by multiple processes
- Related to entitlements - some entitlements auto-grant extensions
Debugging Sandbox Issues
Common Problems and Solutions
Problem: Command fails with "deny(1) process-exec*"
Solution: Add (allow process* (literal "/path/to/command"))
Problem: File access denied Solution: Add appropriate file permission:
(allow file-read-data (literal "/path/to/file"))
(allow file-write-data (literal "/path/to/file"))
Problem: Dynamic library loading fails Solution: Add dyld and library paths:
(allow file-read-data (literal "/usr/lib/dyld"))
(allow file-read-data (literal "/usr/lib/"))
Debug Workflow
Check the denial:
log show --predicate 'eventMessage contains "sandbox"' --last 1mIdentify the operation:
process-exec*- Need process permissionfile-read-metadata- Need file read permissionfile-read-data- Need file data permission
Add minimal permission: Start with
(deny default)and add only what's neededTest incrementally: Add one permission at a time to identify what's required
Security Considerations
Quarantine Attribute
Files created/modified by sandboxed apps get the quarantine attribute, preventing Gatekeeper bypass:
# Check quarantine attribute
xattr -l /path/to/file | grep com.apple.quarantine
# Remove quarantine (if needed)
xattr -d com.apple.quarantine /path/to/file
Entitlements
Key entitlements:
com.apple.security.app-sandbox- Enables sandboxingcom.apple.security.network.server- Network server accesscom.apple.security.temporary-exception.sbpl- Custom SBPL (Apple-approved only)keychain-access-groups- Keychain access
SIP Integration
System Integrity Protection uses sandbox:
- Platform profile in
/System/Library/Sandbox/rootless.conf - Protects system directories
- Cannot be disabled without boot flags
Quick Reference
| Task | Command |
|---|---|
| Run with profile | sandbox-exec -f profile.sb /path/to/app |
| Run with inline profile | sandbox-exec -p "(version 1)..." /path/to/app |
| Trace sandbox checks | sandbox-exec -t trace.out -f profile.sb /path/to/app |
| Inspect process | sbtool <pid> inspect |
| View sandbox logs | log show --predicate 'eventMessage contains "sandbox"' |
| List containers | ls ~/Library/Containers |
| View container config | plutil -convert xml1 container/.com.apple.containermanagerd.metadata.plist -o - |
Best Practices
- Start restrictive: Begin with
(deny default)and add permissions as needed - Use literals over wildcards: More specific = more secure
- Test incrementally: Add one permission at a time
- Check logs: Always verify what's being denied
- Document profiles: Comment your SBPL files
- Review extensions: Understand what extensions your app needs