Skip to content
daniel@cosenza:~/blog
macOSDeep Dive June 10, 2026 4 min read

macOS App Sandboxing and Entitlements Explained

How the App Sandbox confines what an application can access by default, and how entitlements grant it specific, narrow exceptions.

Every application distributed through the Mac App Store, and a growing share of applications distributed outside it, runs inside the App Sandbox — a kernel-enforced confinement that restricts a process to a minimal default set of resources, regardless of what the user running it is otherwise permitted to do. It’s the same “constrain even a fully-privileged actor” philosophy as System Integrity Protection, applied to individual applications instead of the OS as a whole.

Default-deny: the sandbox’s starting point

Without any explicit entitlements, a sandboxed app can’t read files outside its own container, can’t access the network, can’t see other processes, and can’t use most system services — a deliberately restrictive starting point that assumes an app should be able to justify every capability it needs, rather than inheriting the full permissions of the user running it.

codesign -d --entitlements :- /Applications/MyApp.app

The container: an app’s private sandboxed home

A sandboxed app’s own files live in a dedicated container directory, not scattered across the user’s home folder the way an unsandboxed app might behave:

~/Library/Containers/com.example.myapp/Data/

Even the app’s own preferences and documents are redirected into this container transparently — NSUserDefaults and standard file dialogs work normally from the app’s point of view, but the actual files land inside the container rather than directly in ~/Library/Preferences or ~/Documents.

Entitlements: explicit, narrow exceptions

An entitlement is a specific capability an app declares it needs, embedded in its code signature, and granted (or not) at install/launch time. Entitlements are deliberately granular — network client access and network server access are separate entitlements, as are read-only versus read-write file access to specific locations:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.security.app-sandbox</key>
    <true/>
    <key>com.apple.security.network.client</key>
    <true/>
    <key>com.apple.security.files.user-selected.read-write</key>
    <true/>
</dict>
</plist>

An app requesting camera access, microphone access, or Bluetooth needs the corresponding entitlement declared explicitly — and, at runtime, the user is separately prompted by TCC (Transparency, Consent, and Control) to actually grant it, meaning the entitlement is necessary but not sufficient on its own.

Security-scoped bookmarks: persistent access outside the container

A sandboxed app that needs continued access to a file the user explicitly selected (via an Open dialog) beyond the current launch — without re-prompting every time — uses a security-scoped bookmark, a serialized, tamper-resistant reference the system will honor for exactly that file, without granting broader access to its containing folder:

let bookmark = try fileURL.bookmarkData(
    options: .withSecurityScope,
    includingResourceValuesForKeys: nil,
    relativeTo: nil
)
var isStale = false
let restoredURL = try URL(
    resolvingBookmarkData: bookmark,
    options: .withSecurityScope,
    relativeTo: nil,
    bookmarkDataIsStale: &isStale
)
restoredURL.startAccessingSecurityScopedResource()

This is the mechanism behind “this app remembers the folder I gave it access to last time” without the app having been granted broad filesystem access to achieve that — the bookmark is scoped to exactly the file or folder the user picked.

Diagnosing a sandbox violation

When a sandboxed app is denied something it expected to be able to do, the unified logging system records the specific denial, identifying exactly which entitlement (or lack of one) caused it:

log stream --predicate 'subsystem == "com.apple.sandbox"'

Sandboxing versus SIP versus code signing

These three mechanisms are frequently confused because they’re all part of the same broader security model, but each answers a different question: code signing asks “is this binary what it claims to be, unmodified”; SIP asks “is this operation trying to modify a part of the OS that nothing should modify”; the App Sandbox asks “does this specific app have permission to do this specific thing, right now.” A perfectly validly signed, non-SIP-related app can still be denied file access by the sandbox if it lacks the right entitlement — the three checks are independent layers, not redundant versions of the same check.

Why sandboxing pays off even for non-malicious apps

The App Sandbox’s value isn’t limited to defending against deliberately malicious software — it also limits the blast radius of an ordinary security vulnerability in an otherwise legitimate app. A sandboxed PDF reader with a memory-corruption bug in its parsing code is still confined to its container and its declared entitlements even if that bug is successfully exploited, which is precisely the scenario sandboxing is designed to contain: not “will this app try to do something bad,” but “if this app is compromised by someone else’s exploit, how much damage can it actually do.”