Skip to content

0xe8008024 / 0xe8008018: not certificate revocation, and enforced locally on the device #653

Description

@eliabal

Short version: on one free Apple ID I regenerated everything a signer controls
(private key, development certificate, App ID, bundle identifier, provisioning
profile) and the device rejected all of it, while a second free Apple ID installed
fine on the same iPhone minutes of work later. Apple's OCSP responder says the
rejected certificate is good. And with the phone in airplane mode, a profile Apple
had issued seconds earlier was still rejected as banned, so whatever the device is
checking, it already has it locally.

Setup: iloader 2.3.1 on Windows 11, iPhone 16 Pro on iOS 26.6.1 over USB, SideStore
(.io) anisette. Two free accounts, neither on the Developer Program. Account A is EU
and has been sideloading for years, account B is US and never had.

I changed one variable at a time on account A:

what changed result
nothing, reused existing certificate 0xe8008024 profile is banned
new certificate, same key 0xe8008018 identity no longer valid
new certificate after revoking all 0xe8008018
new private key and new certificate 0xe8008018
new bundle ID, new App ID, new profile 0xe8008018
account B, everything else identical installed
account A, phone in airplane mode 0xe8008024

For the bundle ID row I took a minimal app with no extensions, rewrote
CFBundleIdentifier to something that has never existed anywhere, and imported it.
iloader registered a new App ID and Apple issued a matching profile a second before
signing, correct UDID provisioned. Rejected like the rest, so the block does not
follow the app or its App ID.

The certificate in that last rejected signature was issued by WWDR G3, valid for a
year, and the CMS blob carries the full chain (leaf, WWDR G3, Apple Root CA). Its
OCSP status is good, checked minutes after the device refused it. As a control,
two certificates I had deliberately revoked earlier come back revoked with times
matching when I revoked them, so the responder is accurate and current. You can
check this on any affected install by pulling the profile out of the app iloader
staged (it survives a failed install, on success it gets cleaned up):

openssl smime -inform DER -verify -noverify \
  -in embedded.mobileprovision -out profile.plist
python3 -c "import plistlib;open('leaf.der','wb').write(
  plistlib.load(open('profile.plist','rb'))['DeveloperCertificates'][0])"
openssl x509 -inform DER -in leaf.der -out leaf.pem
curl -s https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer -o g3.cer
openssl x509 -inform DER -in g3.cer -out g3.pem
openssl ocsp -issuer g3.pem -cert leaf.pem \
  -url http://ocsp.apple.com/ocsp03-wwdrg303 \
  -header "Host=ocsp.apple.com" -noverify

I also ran it with the phone in airplane mode, PC online, same minimal app on
account A. Apple issued the profile, the app was signed a second later, the device
rejected it about five seconds after that. The profile was seconds old and the
device had never seen it, the phone had no network so it could not look anything up,
and the profile is structurally identical to one issued to the same App ID hours
earlier (same key set, no extra fields, only the DER blob differs because it embeds
the UUID and dates). So the device is holding state keyed on the team and refusing
anything carrying it, offline. Installing offline is not a workaround, and if that
state was pushed to devices then lifting the block probably needs another push
rather than a server-side flag, which makes "this shouldn't be permanent" slower
than it sounds.

The same App ID gave 0xe8008018 on one run and 0xe8008024 on another. I read
those as two surfaces of the same team-level state rather than two separate lists,
surfacing at whichever check gets evaluated first.

Requesting fresh provisioning profiles instead of reusing existing ones is necessary
but not sufficient. A fresh profile does clear 0xe8008024, but installation then
fails at the next check and stays there through every regeneration I tried. There is
nothing left on the client side to fix.

Unrelated to the above, three different failures are getting reported as the same
thing. Anisette and auth problems (HTTP 503 from gsa.apple.com, Failed to get anisette data, error sending request ... listTeams.action, ADIOTPRequest failed (-45061)) all cleared on retry within minutes for me. The signing block is
persistent and account-scoped. LocalDevVPN and device reachability is separate
again. The first two look identical to users and need opposite advice, and asking
for OCSP status in the template would split them automatically.

What I cannot answer is which account attribute triggers it. My two accounts differ
in identity, region and sideloading history, so this separates account from device
but not those three from each other. I would not say Apple bans accounts for
sideloading on this evidence, it is one reading of several, though the region split
is worth noting since at least one report in #583 describes the same EU-blocked,
US-working pattern. I also only have one device, so I cannot test whether a phone
that never received the state would still accept a blocked account. For what it is
worth, the iOS 26+ theory from Discord on Sept 1 does not hold here, since the same
26.6.1 device accepts B and rejects A.

Happy to run more tests, I have a blocked account and a working one on the same
hardware so A/B testing is easy. Related: #583 #571 #580 #589 #605 #611 #633 #638
#641 #644, altstoreio/AltStore#1775, Apollo-Reborn/Apollo-Reborn#1014 (Sideloadly,
same code).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions