writeup

altstore couldn't sign in. apple was sending back an html page.

kisnner obando · september 2026 · altserver 1.6.2–1.7.5 · macos 27 / windows · the thread

a writeup of the september 2026 altstore sign-in breakage: how a "data is not in the correct format" error turned out to be an html 503 page fed into a plist parser, how i got a wrong answer from my own retries, and how the fix ended up as a 39-character string swap inside signed binaries on macos and windows.

this was a community effort in altstoreio/AltStore#1699. the upstream fixes that shipped were written by other people, credited below. my part was the diagnosis, the binary patches for people who couldn't wait for a release, and a second, unrelated failure (-80009) that the first workaround introduced.

tl;dr

the symptom

NSCocoaErrorDomain 3840
Debug Description: Encountered unknown tag html on line 1
AltServer could not sign in with your Apple ID. The data is not in the correct format.

it reads like a credentials problem. people were creating new apple ids, switching vpns, changing regions. none of it helped, because the message wasn't about their account at all.

1. look at the actual traffic

i injected a dylib into stock altserver to log its NSURLSession calls, and captured the grandslam exchange against POST https://gsa.apple.com/grandslam/GsService2:

Request.o=init       ->  200  text/x-xml-plist
Request.o=complete   ->  200  text/x-xml-plist     <-- srp auth succeeds
Request.o=apptokens  ->  503  text/html            <-- "503 Service Temporarily Unavailable"

so apple accepted the password and the anisette data. only the third call was refused, and it came back as an html error page. altsign has no handling for a non-plist body, so the html goes straight into PropertyListSerialization, which fails on <html> at line 1. that's the whole error message.

that also explained why nothing people tried mattered. i reproduced the same result on my home isp, an iphone hotspot and a us vpn exit, with six different anisette servers and two client identities. other reports in the thread added a brand-new apple id and windows with anisette from icloud for windows. same 503 every time.

2. my first conclusion was wrong

i added automatic retries: six attempts over about seven seconds, all 503. i posted that the refusal was deterministic.

it wasn't. every retry reused the same NSURLSession, so every attempt went back over the same pooled connection, pinned to the same failing apple backend. six retries on one connection are one sample, not six. @Calvin-Zikakis had described exactly that bug in AltSign#49. i posted a correction in the thread, because "apple has closed this off" was the wrong thing for people to walk away with.

3. the cause: a user-agent from 2019

@FrakesH identified the trigger: altsign sends

akd/1.0 CFNetwork/978.0.7 Darwin/18.7.0

a macos mojave user-agent, hard-coded. apple's servers started refusing it on apptokens.

to check that before touching any binary, i applied both fixes at runtime to stock altserver 1.7.2 (build 90) through the injected dylib. it rewrote User-Agent on *.apple.com requests and ran every request on a fresh ephemeral URLSession. sign-in and installation worked end to end. on macos 27 i also needed @kimziro's anisette fix for the AOSKit -45070 / empty machineID stage.

4. patching the binaries

a dylib isn't something most people can use. the replacement string is the same length as the old one, 39 characters, so a straight byte swap works without moving anything:

akd/1.0 CFNetwork/978.0.7 Darwin/18.7.0
AuthKit/1 (com.apple.dt.Xcode/3594.4.1)

macos

the string isn't in AltServer itself. it's in the altsign framework, in ascii, twice: AltSign-Dynamic is a universal binary and each architecture slice has its own copy.

AltServer.app/Contents/Frameworks/AltSign-Dynamic.framework/Versions/A/AltSign-Dynamic
  0x62920   -> x86_64 slice
  0x10E210  -> arm64 slice

both sit next to X-MMe-Client-Info. the same layout holds in 1.6.2 and 1.7.2. i downloaded a stock 1.6.2 from apple's cdn to verify it.

the catch is code signing. the stock app has a developer id signature with hardened runtime (flags=0x10000(runtime)). editing the framework invalidates it:

AltServer.app: invalid signature (code or signature have been modified)

so the patch has to end with an ad-hoc re-sign:

APP="/Applications/AltServer.app"
F="$APP/Contents/Frameworks/AltSign-Dynamic.framework/Versions/A/AltSign-Dynamic"
cp -R "$APP" ~/Desktop/AltServer-backup.app
perl -pi -e 's/akd\/1\.0 CFNetwork\/978\.0\.7 Darwin\/18\.7\.0/AuthKit\/1 (com\.apple\.dt\.Xcode\/3594\.4\.1)/g' "$F"
codesign --force --deep --sign - "$APP"
codesign --verify --deep --strict "$APP" && echo OK

@angel-knights confirmed it on 1.6.2 under macos 10.15, a combination i couldn't test.

windows

i'd said windows users had no path because altserver for windows isn't open source. that was wrong: a string swap doesn't need source. i don't have a windows machine, so i took the official installer apart instead (altinstaller.zip → AltInstaller.msi → embedded cab) and read AltServer.exe 1.7.4.0 directly:

i posted a powershell script that backs up the file, refuses to run unless it finds exactly one occurrence, and writes the new bytes in place. @akgang-rgb and @BorbushArtem confirmed it on windows. @BorbushArtem's version was better than mine: it checks both program files paths, asserts the length match before writing, and searches through an iso-8859-1 round-trip instead of my byte loop. i pointed people to theirs.

the altstore app on the phone carries its own copy of altsign, so patching altserver fixes sign-in on the computer only. @spaceace90 found the equivalent swap inside the ipa.

5. the release that didn't fix it

altserver 1.7.5 shipped on sep 8. i pulled it from the official sparkle feed and checked:

AltServer.app/Contents/MacOS/AltServer
  0x111070  -> x86_64 slice   akd/1.0 CFNetwork/978.0.7 Darwin/18.7.0
  0x27E6D0  -> arm64 slice    akd/1.0 CFNetwork/978.0.7 Darwin/18.7.0

same stale string. altsign was now statically linked, so the patch target had moved from the framework to the main executable. and since sparkle replaces the whole app, updating silently undid anyone's patch. AltSign#52, the connection-reuse fix, had been merged seven hours after 1.7.5 was cut, so it wasn't in any release yet.

6. a second bug, caused by the workaround

some people who used a rebuilt altserver started getting -80009 MID is invalid instead. that's a different failure: apple doesn't accept the machine identity.

i probed the three aoskit calls directly on macos 27:

retrieveOTPHeadersForDSID:  ->  {}            (broken)
machineSerialNumber         ->  <real serial> (still works)
machineUDID                 ->  <real udid>   (still works)

only one of them was broken. the macos 27 anisette fix bundled in that build hooks only retrieveOTPHeadersForDSID: and provisions a synthetic identity, which on my machine had serialNumber: "0" and a random deviceID. altserver then sent that synthetic machineID next to the host mac's real serial and udid. the request described two different machines, and apple rejected it.

@oddharsh had already found that gap in anisette-fix#4, which hooks the serial and udid too so the whole set describes one identity. the measurement showed why it was needed: hooking one call out of three leaves the identity half real and half synthetic.

how it ended

mistakes i made in public

takeaways

links