Beyond Prompt Injection: Hacking Apple's Private Cloud Compute
Sign in<br>Subscribe
Drinor was awarded $150,000 for CVE-2026-20685 targeting Apple's Private Cloud Compute, the inference backbone of Apple Intelligence capabilities.<br>This work is my contribution to Sentry's AI Security research initiative, run through SARC, the Sentry Applied Research Center. Our SARC focuses on evaluating systems that carry the most consequence as AI moves into everyday technologies. Private Cloud Compute is a natural target for that work, since it underwrites the privacy guarantees behind Apple Intelligence.<br>There will be a technical paper released that's more detailed in the coming weeks, so stay tuned!<br>Private Cloud Compute is becoming ever more important as the core component of Apple Intelligence features. It is built so a server can process your data with close to the privacy guarantees your iPhone gives you on-device for AI inference requests. I found a path traversal in the code that provisions PCC nodes, darwin-init, that lets an attacker write files as root and compromises privacy and security guarantees in PCC. Apple assigned it CVE-2026-20685.<br>I found the vulnerability through Apple's Virtual Research Environment. The exploit is pretty cool and involved writing files as root during boot and redirecting the node's inference (and other) telemetry to a server I controlled. I think it's a pretty cool find. Besides the exploit itself, I'll explain more about what PCC is and why its guarantees are important for Apple and integrating AI in its products. I then talk about the boot window, the vulnerable component itself, and finally the exploit and the impact related to it.<br>What is PCC and how it's related to AI<br>Private Cloud Compute is Apple's server-side infrastructure for the Apple Intelligence requests that are too large or complex to run on the phone. Apple's privacy claim for it rests on three important mechanisms.<br>Stateless. A node processes a request in memory and keeps no user data across requests or reboots.
Attested. Before your device sends anything, it verifies cryptographically, against a public transparency log, that the node runs only the software Apple published.
Sealed observability. Logs and metrics pass through sealed audit tables, so only specific pre-approved fields leave a node.<br>Definitions<br>A few terms clarify the rest of the blog.<br>A PCC node is one server in the fleet, a hardened DarwinOS.<br>A cryptex is a cryptographically sealed extension, a signed bundle of code and data mounted onto a node at boot; PCC ships its operating system and services as cryptexes.<br>darwin-init is the first userspace process on a booting node, PID 1, running as root: it fetches the node's configuration, downloads and extracts the cryptexes, installs them, and triggers a userspace reboot into the running system.<br>The VRE (Virtual Research Environment) boots a genuine PCC image in a VM so researchers can test it.<br>The trust boundary is Apple's line between inside PCC, where your data is protected, and outside, where it is not, and attestation is how your device checks that a node is genuine and running only published software before trusting it.<br>The boot window: darwin-init runs as root<br>A PCC node's first userspace process is darwin-init, PID 1, root. It resolves a configuration source, downloads the system cryptexes, extracts them, personalizes and installs them, then triggers a userspace reboot (USR) that brings up the steady-state services.<br>Two facts about that boot window are important. First, darwin-init writes to the writable data volume as root before any service that enforces the node's steady-state assumptions is running. Whatever it leaves on disk is present when the node boots up.<br>Secondly, Cryptexes install one at a time. Its checks compare the result against the requested configuration. If one cryptex fails to install, the check fails, and USR doesn't continue, leading to the node hanging with no services.<br>Figure 1. How a PCC node boots. darwin-init resolves its configuration, fetches and extracts cryptexes, runs the empty validate(cryptexConfig:) stub, personalizes and installs, then triggers the userspace reboot that starts the post-boot services.PCC's Extractors<br>When darwin-init downloads an artifact, it reads the first four bytes to pick an extractor.
Magic<br>Type<br>Extractor
AEA1<br>Apple Encrypted Archive<br>extractAppleEncryptedArchive
AA01<br>Apple Archive<br>extractUncompressedAppleArchive
anything else<br>tar / gz / bz2 / zip / cpio<br>extract(to:)
A tar archive's ustar signature sits at byte offset 257, well past the four-byte window. Since tar did not match a known magic, it falls through the default branch to the generic extract(to:).<br>The vulnerable function<br>extract(to:) does this:<br>guard let cStr = archive_entry_pathname(entry) else { continue }<br>let str = String(cString: cStr)
// update entry pathname relative to output dir<br>let pathname = path.appending(str)<br>archive_entry_set_pathname(entry,...