apple / apple/containerization
Clarify `sandbox-exec` deprecation timeline and provide a replacement for non-App-Store process sandboxing
- Dominant language
- Swift
- Stars
- 8.9k
- Forks
- 359
- Avg merge
- 2d 20h
- Merged PRs (30d)
- 13
Description
## Problem
`sandbox-exec(1)` is the only documented mechanism for applying Seatbelt
(TrustedBSD MAC) policies to arbitrary user-space processes on macOS without
enrolling in the App Store or using Xcode entitlements. Apple marks it as
deprecated:
```
$ sandbox-exec -f /dev/null /usr/bin/true
WARNING: sandbox-exec is deprecated. Consider adopting the App Sandbox instead.
```
Despite the deprecation banner, there is no published replacement that covers
the use case of server-side / CLI process sandboxing:
- **App Sandbox** requires code signing with the
`com.apple.security.app-sandbox` entitlement and an Xcode project. It is
designed for GUI apps distributed through the Mac App Store, not for
headless server processes compiled with `go build`.
- **Endpoint Security framework** provides observation and authorization
callbacks but does not offer a declarative sandbox profile that restricts
a child process at exec time.
- **System Extensions** are distribution-gated and inappropriate for
per-process isolation of containers.
We use `sandbox-exec` in `containerd-shim-darwin` to enforce filesystem,
network, and process restrictions on darwin-native container workloads. Our
enforcement bound is documented and tested:
[containerd-shim-darwin/SECURITY.md](https://github.com/SCKelemen/darwin-k8s/blob/main/containerd-shim-darwin/SECURITY.md)
covers 40/42 blocked escape vectors (95.2%).
## Use case
darwin-k8s runs trusted darwin/arm64 Go binaries as native macOS processes
under a Seatbelt profile applied via `sandbox-exec -f `.
This provides:
- Filesystem allow/deny by path pattern
- Network socket deny (bind, connect, listen)
- Process-exec restriction (only the container binary can exec)
- Signal restriction (only self)
- Mach service restriction (subset of `mach-lookup` allowed)
We need answers to three questions:
1. **Will `sandbox-exec` be removed in a specific future macOS version?**
(So we can plan migration timing.)
2. **Is there a non-deprecated equivalent** for applying Seatbelt policies to
processes that are not signed with App Sandbox entitlements? (E.g., a
documented `sandbox_init_with_parameters` C API, or a new framework.)
3. **Will Apple Containerization eventually offer a "lite" isolation mode**
that sandboxes a darwin/arm64 process without spinning up a Linux VM?
(This would let us retire `sandbox-exec` entirely in favor of the
framework.)
## Reproducer
```bash
$ /usr/bin/sandbox-exec -f ./containerd-shim-darwin/test/profiles/deny-default.sb \
./containerd-shim-darwin/test/hello/hello
WARNING: sandbox-exec is deprecated. Consider adopting the App Sandbox instead.
Hello from sandbox
```
The binary runs correctly under the profile, but the deprecation warning is
emitted to stderr on every invocation (macOS 15 Sequoia, Apple Silicon).
Our test suite (`containerd-shim-darwin/test/security_test.sh`) asserts the
enforcement bound: 40 of 42 escape vectors blocked, with the remaining 2
(raw `socket()` fd creation and Mach IPC for Go runtime) documented as
Darwin kernel limits that `sandbox-exec` cannot address.
## Proposed resolution
Any of the following would unblock us:
1. **Publish a supported C API** (e.g., `sandbox_init_with_parameters` or
equivalent) that accepts a Seatbelt profile and applies it to a child
process, without requiring App Sandbox entitlements.
2. **Add a native-process sandboxing mode to Apple Containerization** — a
`DarwinProcess` or `NativeContainer` type that applies a security policy
to a darwin/arm64 binary without the overhead of a Linux VM.
3. **Document the deprecation timeline** so integrators can plan migration
(even if the replacement is "use VMs for everything").
## Workarounds we've tried
1. **Continue using `sandbox-exec` despite deprecation** — works on macOS 15.
Risk: Apple removes it without warning in a future release.
2. **Fall back to Linux VMs for all workloads** — eliminates the native
darwin path entirely. Increases startup latency from <5ms to ~800ms and
adds 128MB+ RAM overhead per pod. Defeats the purpose of running
darwin/arm64 binaries natively.
3. **`setrlimit` + `taskpolicy -b` without sandbox** — provides resource
limits but zero filesystem/network/process isolation. Unacceptable for
any security-conscious deployment.
Contributor guide
Assessment
This issue has not been assessed yet.