fairplay-decrypt: Offline FairPlay IPA Decryption
A public tool recovers a reusable 16-byte FairPlay account credential from a jailbroken iPhone, then decrypts matching IPAs that account owns, offline.
TL;DR
fairplay-decryptis a GPLv3 tool that decrypts FairPlay-encrypted App Store IPAs without launching the app. It uses a 16-byte credential for the Apple Account that owns the IPA.- The retriever needs a jailbroken iPhone on iOS 10 or later with root SSH and one app installed from that account. Decryption then runs offline on macOS or Linux with Python 3.9 or later.
- The weakness is a reusable account credential that unwraps each matching app's key record. One capture decrypts the matching IPAs that account owns. No CVE is assigned, and CISA KEV catalog 2026.11.10 has no FairPlay entry.
- Treat the IPA as public when the account credential can be captured. Keep secrets server-side, detect repackaged builds, and install apps only from the App Store. See "How do I fix it?".
Am I affected?
You are exposed if your app ships as a FairPlay-encrypted arm64 IPA and an attacker can get a credential for an Apple Account that owns it. All of these must hold:
- Your App Store build is encrypted with FairPlay. The tool only handles arm64 Mach-O slices with
LC_ENCRYPTION_INFO_64and a non-zerocryptid. - The attacker holds a 16-byte credential of the matching type for an Apple Account that owns the app, or a reusable model recovered from a Mac enrollment tied to it.
- The attacker has the IPA. They can buy it with that account, receive it from a partner, or steal it.
- They can run the tool on macOS or Linux. Decryption needs no network access to Apple or to your servers.
This is not a remote vulnerability in the app. It is a property of the FairPlay wrapper around the IPA, and the capture step needs a compromised device or an enrolled Mac. A credential from one account does not decrypt an app owned by another account. The tool does not handle FairPlay Streaming video, 32-bit binaries, or IPAs that are not encrypted.
A regular credential covers regular App Store apps. The retriever README says Apple Arcade apps need a separate Arcade credential, so one capture does not cover both types.
| Capture route | What the attacker needs | What it yields |
|---|---|---|
Jailbroken iPhone (fairplay-decrypt) |
iOS 10 or later, root SSH, an installed app from the target account, and a Mac with Xcode and ldid to build the retriever |
A 16-byte account credential; offline decryption of matching IPAs that account owns |
Enrolled Mac (UnfairPlay) |
A Mac signed in to the Mac App Store, one iPhone app installed and opened, and a matching IPA | A reusable enrollment model; decryption of other IPAs from the same enrollment |
| Leaked credential | A 16-byte credential from either route, and an IPA the account owns | Offline decryption with no device |
Check whether an IPA is encrypted. On macOS, extract the main binary and read its encryption load command:
unzip -p App.ipa Payload/App.app/App > /tmp/App
otool -l /tmp/App | grep -A4 LC_ENCRYPTION_INFO_64
codesign -dv --verbose=4 /tmp/App
A cryptid of 1 means the pages are encrypted. A value of 0 means the binary is already clear. Replace Payload/App.app/App with the executable path from the IPA. The codesign command prints the TeamIdentifier of the signature, which you compare with your own.
How do I fix it?
The repository publishes no fixed release, because it is the decryption tool and not a product with a patched version. These steps reduce exposure and limit what a decrypted copy reveals:
- Treat the decrypted IPA as public. Remove API keys, signing secrets and proprietary algorithms that must remain confidential. A client-side secret is readable once the pages are clear.
- Move sensitive decisions to your server. Authorize actions server-side with short-lived tokens, and do not trust a value that ships in the binary.
- Add repackaging detection and server-side attestation. Apple's App Attest and DeviceCheck can flag modified clients, but they do not stop decryption.
- For users, install apps only from the App Store or TestFlight. For managed fleets, block installation from outside the managed catalog.
- If you believe an account credential was captured, stop using that account for distribution and treat every IPA from it as exposed. Review its purchase history.
These steps do not prevent decryption of an IPA the account owns. They limit what the decrypted copy reveals and how it can be misused.
What is the root cause?
FairPlay encrypts each 4 KB page with a key derived from two files in SC_Info, and the chain starts at a 16-byte account credential. The cipher is AES-128. The weakness is where the root secret is kept, not a broken cipher.
The three files that matter
<Name>.sinfis an atom tree with the accountname, a 16-byteiviv, and a 440-byte or 448-byteprivrecord.<Name>.supfor<Name>.v5.supfholds one 32-byte record per encrypted page: a 16-byte wrapped key and a 16-byte AES-CBC IV.- The arm64 Mach-O header carries
LC_ENCRYPTION_INFO_64withcryptoff,cryptsizeandcryptid, which locate the encrypted pages.
derive_work16() turns the account credential and the priv record into a 16-byte per-app work key. In the snippet, name, iviv, credential and raw_priv are the SINF fields and the 16-byte credential read by the parser. The key is the credential XORed with the byte 0x30, not the credential alone. The IV is the MD5 of the account name and iviv:
iv = hashlib.md5(name + iviv).digest()
op = Cipher(algorithms.AES(_xor(credential, b"0" * 16)), modes.CBC(iv)).decryptor()
clear = op.update(raw_priv) + op.finalize()
if clear[:4] != b"itun" or clear[20:24] != b"key " or clear[44:48] != b"iviv":
raise ValueError("credential does not decode this SINF priv record")
return clear[24:40]
derive_page_key() takes the wrapped 16-byte record, the page index and the work key. It encrypts three 16-byte source blocks with AES-128-ECB under the work key, then mixes them through a custom transform called finish():
a, b, c = (
struct.unpack(">8H", block_transform(s, work))
for s in source_blocks(wrapped, absolute_index)
)
return struct.pack(">8H", *finish(_xor_int(finish(_xor_int(finish(a), b)), c)))
finish() runs four 16-bit rounds and four 32-bit rounds of additions, squarings and XORs. The code comments mark one carry as kept and the other as dropped. That transform is obfuscation on top of AES, not a second secret. The 16-byte result is the AES-CBC key for the page, and the next 16 bytes of the SUPF record are its IV.
The per-app key is encrypted under an account secret, so one credential unwraps the priv record of each matching app that the account owns. The retriever recovers that credential on the device. It sets hardware breakpoints on fairplayd's selector function and triggers a license operation through an installed app.
The retriever captures the selector output and keybag state, then combines that state with the device UDID and the tool's tables to produce the 16-byte file. The design trusts the device OS to keep fairplayd's state private. A jailbroken device with root access does not provide that trust boundary. That is the design weakness: the credential is account-wide, reusable and recoverable from user space on a compromised device.
How is it exploited?
An attacker who controls a jailbroken iPhone and an Apple Account that owns the target app recovers one credential and decrypts the matching IPAs offline. The public tool follows this path:
- Prepare a jailbroken iPhone on iOS 10 or later with root SSH access, and install at least one App Store app from the target account.
- Build the retriever on a Mac with Xcode,
ldid,idevice_idandiproxy, then runcredential-retrieval/retrieve.pyagainst the device. - The retriever sets breakpoints in
fairplayd, launches an installed app to trigger a license operation, captures the selector output and keybag state, and writescredential.bin. - Obtain the target IPA from the same Apple Account.
- Run
decrypt.pywith the IPA and the credential. It parses the Mach-O encryption command, the SINF record and the SUPF table, derives the work key and each page key, decrypts the pages, clearscryptid, and writes a new IPA. - Re-sign the output if it must be installed. Decryption clears the encryption marker but does not create a valid code signature.
Nothing in the decryption path contacts Apple. The only device interaction is the capture step. The decryptor is pure Python and runs on macOS or Linux.
How does the attack flow?
A jailbroken device observes fairplayd to recover the account credential, and the credential unwraps each app key so the pages decrypt offline.
reused for every owned app"] D --> E["Unwrap SINF priv into the app work key"] E --> F["Derive page keys from SUPF records"] F --> G["Decrypt arm64 pages and clear cryptid"]
What can an attacker do?
An attacker with the credential can decrypt the matching IPAs that the Apple Account owns, offline and repeatedly, then read or repackage their code and assets. The impact is confidentiality and repackaging, not remote code execution.
The conditions are part of the impact:
- The app must be owned by the credential's account and match its type. The README says each credential works with apps from the Apple Account it came from, and an Arcade app needs the separate Arcade credential.
- The IPA must contain encrypted arm64 slices with a supported SINF and SUPF pair.
- The attacker needs a copy of the IPA.
- Repackaging for installation needs a signing identity. The tool does not sign.
- Decryption does not bypass server-side authentication, business logic or App Attest. Those checks still run when the repackaged app calls your servers.
A decrypted IPA exposes Swift and Objective-C code, strings, embedded configuration, API endpoints, and any key or token that shipped in the binary. That shortens vulnerability research and makes repackaging easier. An attacker can inject a framework or change assets, re-sign the bundle, and distribute it outside the App Store.
A second public project, UnfairPlay, recovers a reusable model from an enrolled Mac instead of a jailbroken iPhone. Its README says one model decrypts other personalized IPAs from the same enrollment and can convert an iOS IPA into a macOS layout. That lowers the barrier from a jailbroken phone to a Mac App Store account. The project appeared on October 25, 2026, six days after fairplay-decrypt's first commit.
UnfairPlay also warns that its output keeps the input's SC_Info licenses and iTunesMetadata.plist, which identify the Store account, unless the operator strips them. A carelessly shared decrypted IPA can therefore expose the account identity as well as the code.
On November 12, 2026, the fairplay-decrypt repository had more than 2,400 stars and 375 forks. Interest is not exploitation: no attack using the tool is reported in the project or the sources reviewed.
Use the tool only on apps you are authorized to analyze. The decrypt command describes its input as an authorized IPA.
Why does the fix work?
No fixed release exists to quote, so nothing in the project closes the design weakness. A fix would have to change the key hierarchy, not one parsing function. Three changes would raise the cost:
- Bind the per-app key to a hardware secret that the OS cannot read, such as the Secure Enclave, and attest the OS before releasing it.
- Deliver a per-app, per-session key from a server that checks the device and the account, instead of deriving it from an account credential held on the device.
- Rotate the credential scheme and invalidate captured credentials when abuse is detected.
None of these is a one-line patch, and each still trusts the device to some degree. A jailbroken OS can observe a user-space daemon even when a key is wrapped. In this case, client-side DRM did not keep the code confidential from a device owner with kernel access.
The project keeps tracking Apple's changes. It added iOS 10 to 12 retrieval, 16 KB page support, SUPF version 5, multiple arm64 slices and Apple Arcade credentials. No CVE is assigned to fairplay-decrypt, and the project has no release that removes the account-credential dependency.
How do I check if I was compromised?
A decrypted copy leaves no trace on your servers, so check for repackaged builds and for account-level credential exposure. For each distributed build, look for these leads:
- A
cryptidof 0 in a build that should be encrypted. - A code signature whose TeamIdentifier is not yours.
- A bundle identifier,
Info.plistorembedded.mobileprovisionthat differs from your release. - Injected frameworks or additional
SC_Infofiles. - Distribution outside the App Store or TestFlight.
Extract the main binary and inspect it:
unzip -p Suspicious.ipa Payload/App.app/App > /tmp/App
otool -l /tmp/App | grep -A4 LC_ENCRYPTION_INFO_64
codesign -dv --verbose=4 /tmp/App
A clear binary plus a signature from another team is a strong lead, not proof of decryption. An unencrypted build is not proof that the copy was decrypted.
On the server, review App Attest and DeviceCheck failures, jailbroken-device signals, and API clients with unexpected versions or missing integrity headers. These are leads too, not proof. The project publishes no indicators of compromise. Decryption is an offline file operation and does not call home, so an attempt that failed may leave no trace.
Timeline
- 2026-10-19: The
EthanArbuckle/fairplay-decryptrepository gets its first public commit. - 2026-10-22: The README confirms iOS 15 support.
- 2026-10-23: A commit adds iOS 10 to 12 credential retrieval.
- 2026-10-25: The
UnfairPlaymacOS project is created. - 2026-10-30: The project adds a GPLv3 license and Apple Arcade credential retrieval.
- 2026-11-08: The latest commit replaces Arcade capture with FairPlay IOKit observation.
FAQ
Is there a CVE for fairplay-decrypt?
No. The project is a research tool, not a product vulnerability with a patched version. NVD returns no FairPlay record for it as of November 12, 2026, and CISA KEV catalog 2026.11.10 lists no FairPlay entry.
Does it need a jailbreak?
For fairplay-decrypt, yes at capture time. The retriever needs a jailbroken iPhone with root SSH. Decryption itself runs on macOS or Linux without the phone. The separate UnfairPlay project uses an enrolled Mac instead of a jailbroken iPhone.
Does one credential decrypt every app?
It decrypts the matching IPAs from the credential's Apple Account. A regular credential covers regular apps, and the README says Arcade apps need a separate Arcade credential. It does not decrypt apps owned by other accounts, and it does not decrypt FairPlay Streaming video.
Is the output installable?
Not as it is. The tool clears cryptid but does not re-sign the binary. iOS requires a valid signature, so the output must be re-signed with a provisioning profile before installation.
Which apps and iOS versions are covered?
The retriever says iOS 10 or later. The decryptor supports arm64 Mach-O slices, SUPF versions 3 and 5, and 440-byte or 448-byte SINF priv records. It does not handle 32-bit-only apps or unencrypted binaries.
Is it exploited in the wild?
No attack using the tool is reported in the project or the sources reviewed as of November 12, 2026. It is not in CISA KEV. The star and fork counts show interest, not exploitation.
References
EthanArbuckle/fairplay-decryptrepository, README, with the 16-byte credential, supported formats and offline decryption: https://github.com/EthanArbuckle/fairplay-decrypt/blob/main/README.md (checked November 12, 2026)core.pyat commit d81d98b13656c9dbb340f04dd0838137278f44a5, the SINF, SUPF and page-key derivation: https://github.com/EthanArbuckle/fairplay-decrypt/blob/d81d98b13656c9dbb340f04dd0838137278f44a5/core.py (checked November 12, 2026)decrypt.pyat the same commit, the IPA input and output path: https://github.com/EthanArbuckle/fairplay-decrypt/blob/d81d98b13656c9dbb340f04dd0838137278f44a5/decrypt.py (checked November 12, 2026)credential-retrieval/README.md, the jailbroken-device requirements, iOS 10 or later, and the reusable account credential: https://github.com/EthanArbuckle/fairplay-decrypt/blob/main/credential-retrieval/README.md (checked November 12, 2026)credential-retrieval/credential/observer.c, the hardware breakpoints and the FairPlay observer: https://github.com/EthanArbuckle/fairplay-decrypt/blob/main/credential-retrieval/credential/observer.c (checked November 12, 2026)credential-retrieval/credential/credential.c, the selector, keybag and credential derivation: https://github.com/EthanArbuckle/fairplay-decrypt/blob/main/credential-retrieval/credential/credential.c (checked November 12, 2026)- Commit 5fdf16b48ea4a2a32950641aba23dd3063c34856, the first public commit on October 19, 2026: https://github.com/EthanArbuckle/fairplay-decrypt/commit/5fdf16b48ea4a2a32950641aba23dd3063c34856 (checked November 12, 2026)
- Commit 9e5aa3ea290d79c3320190004dc512e034d99484, the GPLv3 license on October 30, 2026: https://github.com/EthanArbuckle/fairplay-decrypt/commit/9e5aa3ea290d79c3320190004dc512e034d99484 (checked November 12, 2026)
- Commit 8350383e2e9050f7a77197bf32545ddbef90b57c, Apple Arcade credential retrieval on October 30, 2026: https://github.com/EthanArbuckle/fairplay-decrypt/commit/8350383e2e9050f7a77197bf32545ddbef90b57c (checked November 12, 2026)
- Commit 5e35c7a, iOS 10 to 12 support on October 23, 2026: https://github.com/EthanArbuckle/fairplay-decrypt/commit/5e35c7a (checked November 12, 2026)
EthanArbuckle/fairplay-decryptcommit history, with the iOS 10 to 12, 16 KB page, SUPF v5, multiple-slice and Arcade changes: https://github.com/EthanArbuckle/fairplay-decrypt/commits/main (checked November 12, 2026)DrWhax/unfairplayrepository, README, the enrolled-Mac route and the reusable model: https://github.com/DrWhax/unfairplay/blob/main/README.md (checked November 12, 2026)DrWhax/unfairplayrepository page, created October 25, 2026: https://github.com/DrWhax/unfairplay (checked November 12, 2026)vnc0/fairplay-scinfo, file-format documentation for SINF, SUPF and the wrapped page keys: https://github.com/vnc0/fairplay-scinfo (checked November 12, 2026)- Apple,
loader.h, theLC_ENCRYPTION_INFO_64structure and thecryptidfield: https://github.com/apple-oss-distributions/xnu/blob/main/EXTERNAL_HEADERS/mach-o/loader.h (checked November 12, 2026) - CISA, Known Exploited Vulnerabilities catalog JSON, version 2026.11.10, no FairPlay entry: https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json (checked November 12, 2026)
- NVD search for FairPlay, no record for the project as of November 12, 2026: https://nvd.nist.gov/vuln/search/results?query=fairplay&search_type=all (checked November 12, 2026)
EthanArbuckle/fairplay-decryptrepository page, more than 2,400 stars and 375 forks on November 12, 2026: https://github.com/EthanArbuckle/fairplay-decrypt (checked November 12, 2026)