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
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 <profile> <binary>.
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:
- Will
sandbox-exec be removed in a specific future macOS version?
(So we can plan migration timing.)
- 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.)
- 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
$ /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:
- 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.
- 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.
- Document the deprecation timeline so integrators can plan migration
(even if the replacement is "use VMs for everything").
Workarounds we've tried
- Continue using
sandbox-exec despite deprecation — works on macOS 15.
Risk: Apple removes it without warning in a future release.
- 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.
setrlimit + taskpolicy -b without sandbox — provides resource
limits but zero filesystem/network/process isolation. Unacceptable for
any security-conscious deployment.
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:
Despite the deprecation banner, there is no published replacement that covers
the use case of server-side / CLI process sandboxing:
com.apple.security.app-sandboxentitlement and an Xcode project. It isdesigned for GUI apps distributed through the Mac App Store, not for
headless server processes compiled with
go build.callbacks but does not offer a declarative sandbox profile that restricts
a child process at exec time.
per-process isolation of containers.
We use
sandbox-execincontainerd-shim-darwinto enforce filesystem,network, and process restrictions on darwin-native container workloads. Our
enforcement bound is documented and tested:
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 <profile> <binary>.This provides:
mach-lookupallowed)We need answers to three questions:
sandbox-execbe removed in a specific future macOS version?(So we can plan migration timing.)
processes that are not signed with App Sandbox entitlements? (E.g., a
documented
sandbox_init_with_parametersC API, or a new framework.)that sandboxes a darwin/arm64 process without spinning up a Linux VM?
(This would let us retire
sandbox-execentirely in favor of theframework.)
Reproducer
$ /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 sandboxThe 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 theenforcement bound: 40 of 42 escape vectors blocked, with the remaining 2
(raw
socket()fd creation and Mach IPC for Go runtime) documented asDarwin kernel limits that
sandbox-execcannot address.Proposed resolution
Any of the following would unblock us:
sandbox_init_with_parametersorequivalent) that accepts a Seatbelt profile and applies it to a child
process, without requiring App Sandbox entitlements.
DarwinProcessorNativeContainertype that applies a security policyto a darwin/arm64 binary without the overhead of a Linux VM.
(even if the replacement is "use VMs for everything").
Workarounds we've tried
sandbox-execdespite deprecation — works on macOS 15.Risk: Apple removes it without warning in a future release.
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.
setrlimit+taskpolicy -bwithout sandbox — provides resourcelimits but zero filesystem/network/process isolation. Unacceptable for
any security-conscious deployment.