- Platforms: macOS 15.x (Sequoia), Intel-Based
- App type: Endpoint Security (ES) client, notarized Developer ID app + LaunchDaemon
- Goal: Boot-time ES client that runs on any Mac (managed or unmanaged)
Summary
Our ES client launches and functions when started manually (terminal), but when loaded as a LaunchDaemon it fails to initialize the ES connection with:
(libEndpointSecurity.dylib) Failed to open service: 0xe00002d8: Caller lacks TCC authorization for Full Disk Access
We can’t find a supported way to grant Full Disk Access (SystemPolicyAllFiles) to a system daemon on unmanaged Macs (no MDM). Local installation of a PPPC (TCC) profile is rejected as “must originate from a user-approved MDM server.”
We’re seeking confirmation: Is MDM now the only supported path for a boot-time ES daemon that requires FDA? If so, what’s Apple’s recommended approach for unmanaged Macs?
Environment & Artifacts
Binary (path placeholder): /Library/Application Support/<VENDOR>/<PRODUCT>/App/<AppName>.app/Contents/MacOS/<es-binary>
- Universal (x86_64 + arm64)
- Notarized, hardened runtime; Developer ID Team <TEAM_ID>
- Entitlements include:
- com.apple.developer.endpoint-security.client (present)
Daemon plist (simplified; placeholders used):
<?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>Label</key> <string>com.example.esd</string>
<key>Program</key>
<string>/Library/Application Support/<VENDOR>/<PRODUCT>/Platform/<daemon-exec></string>
<key>WorkingDirectory</key>
<string>/Library/Application Support/<VENDOR>/<PRODUCT>/Platform</string>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
</dict></plist>
Designated requirement (abridged & masked):
identifier "<BUNDLE_ID>" and anchor apple generic and certificate 1[...] and
certificate leaf[...] and certificate leaf[subject.OU] = "<TEAM_ID>"
What works
- Launching the ES client manually (interactive shell) succeeds; ES events flow.
- Signature, notarization, entitlements, Gatekeeper: all OK.
What fails (daemon)
- launchctl print system/<label> shows it starts, but Console logs:
-
(libEndpointSecurity.dylib) Failed to open service: 0xe00002d8:Caller lacks TCC authorization for Full Disk Access
-
- System TCC DB shows ES consent rows but no allow for TCCServiceSystemPolicyAllFiles for the daemon binary.
- Installing a PPPC mobileconfig locally (system scope) is blocked as “must originate from a user-approved MDM server.”
Repro (minimal)
- Install app bundle + LaunchDaemon plist above (placeholders).
- Verify entitlements & notarization:
codesign -dvvv --entitlements :- "<path-to-es-binary>"
spctl --assess --type execute -vv "<path-to-es-binary>"
- Start daemon & watch logs:
sudo launchctl bootstrap system "/Library/LaunchDaemons/<your-daemon>.plist"
log stream --style compact --predicate 'process == "<es-binary>" OR subsystem == "com.apple.TCC"' --info
- Observe FDA denial message only in daemon context.
- Attempt to add FDA via PPPC profile (system scope) → rejected unless installed by user-approved MDM.
Questions for Apple
- On macOS 14/15, is Full Disk Access for system daemons strictly MDM-only via PPPC (i.e., not installable locally)?
- Under what conditions would libEndpointSecurity report a Full Disk Access denial at client initialization, given ES consent is distinct from FDA?
- For unmanaged Macs needing boot-time ES processing, does Apple recommend a split: root LaunchDaemon (ES subscription; no protected file I/O) + per-user LaunchAgent (user-granted FDA) via XPC for on-demand disk access?
- Would moving ES connection code into a System Extension change FDA requirements for unmanaged devices, or is FDA still governed by PPPC/MDM?
- If behavior changed across releases, can Apple confirm the intended policy so vendors can document MDM requirements vs. unmanaged install paths?
What we’ve tried
- Verified signature, notarization, hardened runtime, ES entitlement present.
- Confirmed context difference: manual run OK; daemon fails.
- Inspected system TCC: ES consent rows present; no FDA allow for daemon.
- Tried installing system-scoped PPPC locally → blocked as “must originate from a user-approved MDM server.”
- Considered LaunchAgent-only, but ES needs root; evaluating daemon+agent split to keep ES in root and put FDA-gated work in user space.
What we need
- A definitive statement on the supported way to grant FDA to a system daemon on macOS 14/15.
- If MDM PPPC is required, we’ll ship “daemon mode requires MDM” and provide a daemon+agent fallback for unmanaged devices.
- If a compliant non-MDM path exists for daemon FDA on unmanaged Macs, please share exact steps.
Thanks! Happy to provide additional logs privately if helpful.
Our ES client launches and functions when started manually (terminal).
FYI, this is almost certainly because you previously granted Terminal.app FDA, which your client then inherited. Terminal.app does not have any unique/privileged access to the file system.
We can’t find a supported way to grant Full Disk Access (SystemPolicyAllFiles) to a system daemon on unmanaged Macs (no MDM).
The supported way to do this is for the user to grant your daemon FDA through System Setting-> Privacy & Security-> Full Disk Access.
You may have already tried this and found that the interface wouldn't let you select this bare executable:
/Library/Application Support/<VENDOR>/<PRODUCT>/Platform/<daemon-exec>
However, the direct solution to that is simply embed your daemon executable inside an app bundle, as described here. However, this would also be a great time to adopt SMAppService, which would change some of the requirements/behavior here.
Covering some specifics:
- On macOS 14/15, is Full Disk Access for system daemons strictly MDM-only via PPPC (i.e., not installable locally)?
No, not at all. As described above, you may need to package your daemon inside an app bundle, but system daemons can be granted FDA.
- Under what conditions would libEndpointSecurity report a Full Disk Access denial at client initialization, given ES consent is distinct from FDA?
All? Using the ES API requires FDA. Given that privacy, security, and general disruption the ES API can create, requiring FDA was the simplest way to ensure the user wanted the ES client to "work".
- For unmanaged Macs needing boot-time ES processing, does Apple recommend a split: root LaunchDaemon (ES subscription; no protected file I/O) + per-user LaunchAgent (user-granted FDA) via XPC for on-demand disk access?
No, this won't work. As noted above, the ES API requires FDA.
- Would moving ES connection code into a System Extension change FDA requirements for unmanaged devices, or is FDA still governed by PPPC/MDM?
Sort of, but only indirectly. Using a system extension means that your embedded inside an app and your system extension can then inherit the FDA grant given to your app. However, the biggest reason to use a system extension is that it allows you to use NSEndpointSecurityEarlyBoot (from "man EndpointSecurity"):
...
The EndpointSecurity (ES) subsystem is a set of functionality to expose
security-relevant system events to applications (ES clients). ES
clients can either be standalone applications/executables or installed
as system extensions.
If the ES client is a system extension, the following optional keys can
be set in the bundle's Info.plist:
NSEndpointSecurityEarlyBoot
Type: Boolean
If set to TRUE, the ES subsystem will hold up all mounts and third
party executions (anything that is not a platform binary) until all
early boot ES extensions make their first subscription.
However, I think adopting SMAppService would also allow a daemon to inherit FDA from its parent app.
> 5. If behavior changed across releases, can Apple confirm the intended policy so vendors can document MDM requirements vs. unmanaged install paths?
FDA has "always" worked the way.
A definitive statement on the supported way to grant FDA to a system daemon on macOS 14/15.
Making it explicit, FDA can be granted to a LaunchDaemon through System Settings by:
-
Constructing the LaunchDaemon as a bundled application, then granting FDA to that "app". This works on all system versions.
-
Embedding the LaunchDaemon into a parent application and then granting the parent app FDA. This is how FDA is granted to system extensions, but it may also work for other embedding executables, particularly if the embedded executable has also been built as an app bundle (like #1).
__
Kevin Elliott
DTS Engineer, CoreOS/Hardware