Entitlements and code signing
TL;DR: An entitlement is a plist key embedded in a Mach-O code signature that grants the binary a specific privilege (TCC bypass, sandbox exception, debugger access). Abuse paths: weakly signed Apple helpers, inheritance into child processes, and
get-task-allowletting you attach.
What it is
macOS code signing is enforced by AppleMobileFileIntegrity (AMFI) in the kernel and taskgated/taskgated-helper in userland. Every Mach-O has a LC_CODE_SIGNATURE blob: hashes of code pages, the CodeDirectory, a requirement expression, and the entitlements plist. The kernel checks signatures at exec and at Mach-port lookup; entitlements are queried by services (TCC, sandbox, SecKeychain, EndpointSecurity) to authorise privileged operations.
Preconditions / where it applies
- Any local privesc, sandbox escape, or TCC bypass on macOS — the entitlements model is what divides “anybody” from “this specific Apple binary”.
- Apple Silicon enforces code signing for all executable pages; Intel macOS does the same for hardened binaries.
- Particularly relevant on apps shipped with
com.apple.security.cs.disable-library-validationorcom.apple.security.get-task-allow.
Technique
Read what a binary asks for:
1
2
3
codesign -dv --entitlements - /Applications/Foo.app/Contents/MacOS/Foo
codesign -d --requirements - /Applications/Foo.app/Contents/MacOS/Foo
spctl --assess --verbose /Applications/Foo.app
Common abuse patterns:
com.apple.security.cs.disable-library-validation— the app accepts unsigned or third-party-signed dylibs. Plant a dylib named like a weak-linked dependency and load viaDYLD_INSERT_LIBRARIESor a hijack path. Now your code runs inside a process that may hold TCC grants (Full Disk Access, Accessibility, Camera).com.apple.security.get-task-allow— the binary is debuggable.task_for_pidfrom a peer process succeeds and you can inject via Mach ports.com.apple.private.*entitlements on shipped Apple binaries — historically researchers found Apple helpers with sweeping private entitlements (e.g.com.apple.rootless.install.heritable) reachable from a less-privileged context. Hijacking the binary inherits the entitlement.- Inheritance via
posix_spawn/exec— entitlements do not persist across exec to a different binary; they re-evaluate against the new code signature. But child tasks inherit atask_portyou can drive. - Ad-hoc / linker-resigned binaries —
codesign -s -strips real identity but retains structure; combined with disabled library validation this becomes a stealth-injection path on user-installed apps.
Search system for interesting entitlements:
1
2
sudo find /System /Applications -type f -perm -u+x -exec \
sh -c 'codesign -d --entitlements - "$1" 2>/dev/null | grep -q "$2" && echo "$1"' _ {} "get-task-allow" \;
Detection and defence
- EndpointSecurity emits
ES_EVENT_TYPE_NOTIFY_EXECwith the full code-signing info — defenders alert on unexpected entitlements on user-writable paths. - Enable Hardened Runtime + Library Validation on every internally built app; never ship the “disable-library-validation” entitlement to production.
- Use the App Sandbox where possible — entitlements then double as the sandbox’s allow-list, narrowing the blast radius. See macos-sandbox-escape and macos-tcc.
References
- Apple — Code Signing Guide — official API surface.
- Apple — Entitlements reference — list of public entitlements.
- HackTricks — macOS code signing — offensive notes.