Read the user guide for more detail
PolicyWitness is a macOS sandbox witness harness for verifying sandbox policies with observable evidence. Sandbox outcomes are easy to misread without clear attribution and consistent output. PolicyWitness ties each result to a specific runner instance and emits a stable JSON envelope so you can audit, diff, and automate tests without guesswork.
Specimens -> Runs -> Steps -> Evidence
PolicyWitness operates on specimen, packages of SBPL + entitlements and probe plans. The controller launches a fresh runner for each specimen. The runner starts unsandboxed, loads libsandbox, applies the provided policy once, and then executes the probe plan step by step inside the sandbox. Each step performs an explicit attempt, records rc plus errno or kr, and also runs sandbox_check with the same operation and filter so you can compare predicted vs observed outcomes. The runner returns a single JSON result and exits.
Each step may include multiple evidence channels:
- A: in-band attempt result (rc/errno/kr)
- B: deterministic side effects (for example SBPL
send-signal) - C: out-of-band unified-log correlation (best-effort)
- D:
sandbox_checkprediction and "am I sandboxed" confirmation
PolicyWitness supports three runner modes. All three return the same JSON envelope and speak the same NSXPC protocol; they differ only in how the runner process is supplied and registered.
debuggable: built-in XPC service embedded inPolicyWitness.app; no install step.byoxpc: user-supplied.xpcbundle (optionally self-signed) installed withpolicy-witness runner install --kind byoxpc.machme: user-supplied binary registered as a Mach service withpolicy-witness runner install --kind machme.
PolicyWitness treats entitlements as a first-class input alongside SBPL. Register an externally signed runner with the entitlements your probes require, then apply a per-specimen SBPL policy on top to test temporary restrictions or entitlements + SBPL combinations in a single run.
Instrumentation ports are part of the debuggable runner, allowing closer inspection.
dyld_env: report expectedDYLD_*env vars (com.apple.security.cs.allow-dyld-environment-variables); set via an external runner withpolicy-witness runner install --env KEY=VALUE.dylib_load: load a dylib and optionally call a symbol (com.apple.security.cs.disable-library-validation)debug_wait: pause before sandbox apply for debugger attach (com.apple.security.get-task-allow)execmem_probe: attempt RWXmmapand report success/failure (com.apple.security.cs.allow-unsigned-executable-memory)
This repo builds a single distributable app bundle:
PolicyWitness.appContents/MacOS/policy-witness(Rust controller)Contents/MacOS/pw-runner-client(Swift NSXPCConnection wrapper)Contents/MacOS/sandbox-log-observer(Rust unified-log capture helper)Contents/XPCServices/PWRunner.xpc(Swift runner, debuggable mode; one specimen per process)Contents/Resources/Evidence/*(generated manifests: hashes/entitlements,symbols.json)
- Repo orientation: AGENTS.md
- Contributing: CONTRIBUTING.md
- Testing: tests/README.md
- Implementation details:
- Signing/distribution: SIGNING.md
- Using the app and workflows: PolicyWitness.md
- CLI contract and controller behavior: controller/README.md
- Runner service architecture: runner/README.md