[{"content":"The Apple HomePod Mini has never been jailbroken. The jailbreak community wrote it off after confirming its S5 chip (T8006) falls outside checkm8\u0026rsquo;s range (A5-A11 only). This writeup documents what I believe is the first publicly documented non-invasive security exploration of the HomePod Mini via its USB-C port, covering an interactive iBoot recovery shell session, full binary analysis of the firmware, and AirPlay protocol analysis on the running audioOS.\nTarget: AudioAccessory5,1, Apple S5 (T8006), board b520ap, audioOS 26.3 (Build 23K620), iBoot-13822.80.422.0.2.\nUSB reconnaissance With the HomePod Mini plugged into a Mac via USB-C, ideviceinfo connects over usbmuxd and returns detailed device information. Notably, system_profiler SPUSBDataType returns empty. The Mini communicates exclusively through usbmuxd\u0026rsquo;s TCP-over-USB protocol, not as a raw USB device. Tools like irecovery cannot see it in this state.\nKey identifiers from normal-mode enumeration:\nField Value ChipID 32774 (0x8006, T8006/S5) CPUArchitecture arm64e HardwareModel B520AP ProductType AudioAccessory5,1 ProductName Apple TVOS (audioOS is tvOS under the hood) FirmwareVersion iBoot-13822.80.422.0.2 The device shows TrustedHostAttached: true, meaning lockdownd services are available. NVRAM was also readable: auto-boot = \u0026ldquo;true\u0026rdquo;, usbcfwflasherResult = \u0026ldquo;No errors\u0026rdquo;.\nDFU mode attempts No public method to enter DFU mode on the HomePod Mini has ever been documented. I tried multiple button/power combinations while monitoring USB events:\nHold touch surface, plug USB-C, plug power (held 20 seconds) Plug USB-C, plug power, hold touch surface through recovery Rapid power cycling (3x) with USB connected, hold touch surface Touch surface hold before any power with USB connected Holding both + and - volume zones simultaneously during power-on All attempts resulted in normal boot (white light), recovery mode (orange flashing light), or factory reset (3 beeps). Attempt 3 triggered Siri announcing a WiFi connection issue, confirming it was booting to userspace audioOS.\nThe orange flashing light during standard Finder restore is not iBoot recovery mode. It\u0026rsquo;s a userspace restore daemon running on minimal audioOS.\nEntering iBoot recovery mode Since lockdownd trusts the host Mac, ideviceenterrecovery can instruct the device to reboot into iBoot recovery mode over usbmuxd:\n$ ideviceenterrecovery $(ideviceinfo -k UniqueDeviceID) Telling device with udid 00008006-000629620103C02E to enter recovery mode. Device is successfully switching to recovery mode. The HomePod goes completely dark. No orange light, no white light, total silence. Consistent with every other Apple device\u0026rsquo;s bootloader behavior.\nFirst irecovery session with a HomePod Mini With the device in iBoot recovery mode, irecovery -q connects:\nCPID: 0x8006 CPRV: 0x11 BDID: 0x22 ECID: 0x000629620103c02e CPFM: 0x03 SCEP: 0x01 IBFL: 0x3d SRTG: N/A MODE: Recovery PRODUCT: AudioAccessory5,1 MODEL: b520ap NAME: HomePod mini MODE: Recovery (not DFU). This is iBoot, not SecureROM. SRTG: N/A confirms it; DFU mode would show the SecureROM version tag. CPFM: 0x03 means production fused, both production and security bits set. No debug access.\nInteractive iBoot shell irecovery -s opens an interactive shell:\n======================================= :: :: Supervisor iBoot for b520, Copyright 2007-2025, Apple Inc. :: :: Local boot, Board 0x22 (b520ap)/Rev 0x3 :: :: BUILD_TAG: iBoot-13822.80.422.0.2 :: :: BUILD_STYLE: RELEASE :: ======================================= Entering recovery mode, starting command prompt The shell accepts getenv queries. secure-boot returns 0x1, auto-boot returns false. Most variables return \u0026ldquo;false\u0026rdquo; (not found): boot-args, debug-enabled, firmware-version. The help command returns empty. bgcolor, version, meminfo, devicetree all silently fail. reboot works. irecovery -n returns the HomePod to normal operation.\niBoot binary analysis Firmware acquisition HomePod Mini IPSW files are standard ZIP archives from ipsw.me. The iBoot binary was decrypted using published firmware keys from The Apple Wiki for audioOS 16.6 (Build 20M73):\nIV: 158dd8de55acbe7f475674aa98af825b Key: a1b0fc7917caf43613086e68666139733ceefed3715a0aa4277b986af02118dd The resulting binary is 1,397,928 bytes, arm64e, virtual base 0x180000000.\nCommand table The RELEASE iBoot has an extremely minimal command set. Only infrastructure commands are registered: command, menu_loop, poweroff, idleoff, USB handlers (usb, usb req, usb-hi-current, usb-no-current, usb_serial, vbus poll, usb vbus), and boot flow (main, fsboot, upgrade, recover, recover-once, darkboot).\nDead strings present but unreferenced by code: getenv, setenv, bgcolor, bootx, memboot, reboot, reset, go. These are residual string data from shared object files, compiled out via preprocessor guards.\nCompletely absent: md (memory dump) and mw (memory write) don\u0026rsquo;t exist as strings at all. Not gated, removed entirely.\nSecurity architecture Mitigation Status PAC (Pointer Authentication) Active, 1,683 functions BLRAA (authenticated indirect calls) Active, 244 instances Authenticated returns (RETAB) Active, 1,432 instances Stack canaries Active, 167 functions Image4 chain-of-trust Active Debug commands Completely stripped A11 vs S5: how Apple killed checkm8 To understand how Apple hardened the S5, I compared the HomePod Mini\u0026rsquo;s iBoot against an iPhone X (A11/T8015) iBoot from the same build train. The A11 is the last checkm8-vulnerable chip.\nPAC enabled in iBoot The A11 supports arm64e but Apple never enabled PAC in its iBoot. The S5 has 1,683 PAC-protected functions, 1,432 authenticated returns, and 244 authenticated indirect branches. In the USB code region alone, 455 TBZ checks on bit 62 (PAC signature region). The A11 has zero.\nMetric A11 (iPhone X) S5 (HomePod Mini) pacibsp instructions 0 1,683 BLRAA instructions 0 244 RETAB instructions 0 1,432 Bit 62 checks in USB region 0 455 USB handler shrunk 80x The A11\u0026rsquo;s monolithic USB request handler spans ~16KB with 470 function calls, handling device tree setup, crypto, display init, and battery management inline. The S5 replaced this with a 196-byte thin wrapper making 4 delegated calls.\nComponent A11 S5 USB req handler ~16 KB, 470 BL calls 196 bytes, 4 BL calls DFU setup function ~16 KB, 652 BL calls 72 bytes, 2 BL calls function-reset removed The string function-reset exists in the A11 binary at 0x18004bd8c. This is the USB function reset handler that checkm8 directly exploits (the use-after-free occurs during USB function reset). This string and its associated code are entirely absent from the S5 binary. The functionality was either removed or refactored into a new ausb ctr (audio USB controller) abstraction layer that exists only on S5.\nDeterministic stack canary The iBoot stack canary value is 0x4752440044003631, and it is deterministic, not random. The canary is initialized at 0x1800021e0, which executes before the SVC handler, before MMU setup, and before any entropy subsystem is available. The random_fill() function at 0x18005022c checks a BSS flag that is guaranteed zero at this point, causing it to fall back to a hardcoded seed value.\nThe ASCII content (GRD\\0D061) confirms this is a build tag, not cryptographic randomness. This value is identical across every HomePod Mini running this iBoot version.\nIf any stack buffer overflow exists anywhere in this iBoot build, the canary provides zero protection. This reduces the mitigation stack from three layers (canary + PAC + controlled value) to two.\nCommand parser bounds checking Initial analysis suggested the command tokenizer at 0x180060288 had an out-of-bounds write. The token counter w21 appeared to increment past a CMP w21, 6 soft limit. Deeper analysis of the CCMP/CSEL pattern disproved this:\nCMP w21, 6 ; compare token count CCMP w8, 0, 4, le ; if w21 \u0026lt;= 6: compare next_byte to null ; if w21 \u0026gt; 6: force flags to nzcv=0100 (Z=1) CSEL w8, w25, wzr, eq ; if Z=1: state = 2 (dispatch/exit) When w21 \u0026gt; 6, the CCMP\u0026rsquo;s le condition fails, forcing Z=1 regardless of w8. The CSEL picks w25 = 2 (command dispatch = function exit). Maximum 7 entries (indices 0-6) are written into a 10-slot array. Well within bounds.\nThe command parser is correctly bounded. The CMP + CCMP + CSEL pattern creates an effective hard limit.\nExhaustive iBoot attack surface audit Image4 / DER / ASN.1 parser The DER/ASN.1 parser at 0x180063e88 is Apple\u0026rsquo;s libDER. Every byte read has pointer range validation (start \u0026lt;= ptr \u0026lt; end), the multi-byte length accumulator has overflow detection at each iteration (LSR + CBNZ), indefinite length forms are rejected, non-minimal encodings are rejected, and the final content_start + content_length addition has an explicit overflow check. Strict mode is set for the DFU input path.\nLZFSE / LZSS decompression Three layers protect against decompression overflow: the IM4P header validation caps uncompressed size at ~190MB, the heap allocator adds 0x200 bytes of headroom, and the LZFSE decoder contains 40+ CMP x20 bounds checks.\nausb ctr USB controller The S5 USB stack is fundamentally redesigned:\nNo use-after-free possible. The 6,144-byte USB transfer buffer is calloc()\u0026rsquo;d once at 0x180031d94, stored at BSS 0x18015b9a8, and never freed. Only 2 references exist in the entire binary. Zero indirect calls. The entire USB region (0x18002f000-0x180033000) contains no BLR, BLRAA, or BRAAZ instructions. All calls are direct BL. Fixed sub-buffer layout. 6,144 bytes partitioned at compile-time: EP0 setup 256B, EP0 data out 2048B, EP0 data in 1024B, bulk in 1024B, bulk out 1028B. No dynamic buffer sizing. Minimal state machine. Single abort flag byte, single busy flag byte, single-threaded loop. The bootloader attack surface is effectively closed through static analysis.\naudioOS network attack surface With iBoot exhausted, I shifted to the running audioOS.\nThe root filesystem contains 254 daemons and 3 apps. Four daemons bind network ports:\nDaemon Port Notes remotepairingdeviced Dynamic (TCP) ExposedToUntrustedDevices: true lockdownd 62078 Standard iOS lockdown protocol mDNSResponder 5353 (UDP) Bonjour/DNS-SD racoon 500 (IKE) IPSec VPN (likely disabled) Live Bonjour reconnaissance confirmed AirPlay on port 7000 with acl=0 (no access control, any LAN device can connect).\nOPACK wire format reverse engineering Apple\u0026rsquo;s OPACK is a proprietary binary serialization format used by RemoteXPC and remotepairingdeviced. It is parsed before authentication during the pairing handshake. I reverse-engineered it from __OPACKDecodeObject at 0x19380c320 in CoreUtils.framework.\nTag Range Type Encoding 0x01 NULL No payload 0x02 FALSE No payload 0x03 TRUE No payload 0x04 Terminator End marker 0x05 UUID 16 bytes follow 0x06 Date 8 bytes follow 0x07-0x2F Cached constants Index into pre-registered object table 0x30 Int8 1 byte follows 0x31-0x36 Int16/32/64, Float, Double 2/4/8 bytes follow 0x40 Empty string No payload 0x41-0x60 Short string Length = tag - 0x40 (1-32 bytes inline) 0x61-0x64 String 1-4 byte length prefix + data 0x65+ Data, Array, Dictionary, UID Container types, recursive Arrays and dictionaries are recursive, each call using ~0x70 bytes of stack. Recursion depth limit is 32 levels (CMP w8, 0x20 at 0x19380cd74). Tag 0x64 allows a 4-byte length prefix (up to ~4GB), creating potential allocation overflow in the CFStringCreate path.\nremotepairingdeviced: less open than advertised Despite the ExposedToUntrustedDevices: true flag, the daemon has multiple layers of gating:\nTCP listener disabled by default. The string \u0026quot;Not configuring launchd-managed TCP control channel due to 'deviceAllowTCPControlChannel' not being set to true\u0026quot; reveals the TCP listener requires an explicit flag. Requires prior pairing. TCP channel only activates after at least one host has been paired via USB or Bluetooth. Promptless pairing is USB-only and time-limited. \u0026quot;USB host disconnected; promptless pairing disabled\u0026quot;. Network pairing requires consent via the Home app on a paired iPhone. Bluetooth-triggered listener. The primary discovery path is BLE proximity, not an always-on service. For a LAN-only attacker, the TCP control channel is likely inactive on a stock HomePod Mini. The most promising network target is tvairplayd on port 7000.\nAirPlay protocol analysis Live HTTP probing of tvairplayd:\nRequest Response Auth Required GET /info 200 OK (full device info) No POST /pair-setup 400 (expects body) No, parses pre-auth data POST /fp-setup 400 (FairPlay setup) No, parses pre-auth data The /pair-setup endpoint implements HomeKit pair-setup using SRP-3072. Sending a valid M1 message returned a valid M2 response with a 16-byte salt and 384-byte SRP server public key.\nThe classic SRP-zero bypass (A = 0) was blocked. HTTP 470, Apple validates the SRP public key before computation.\nAfter a single failed M3 message, the HomePod imposed a 64,259-second lockout (~18 hours). Approximately 1.3 attempts per day per HomePod.\n/pair-verify: Curve25519 key exchange To establish a session, I implemented the complete pair-verify protocol. This is the standard AirPlay session establishment flow, documented in the pyatv and pair_ap libraries:\nM1 to M2: Sent Curve25519 public key, received server\u0026rsquo;s ephemeral key + encrypted data. Shared secret: Curve25519 ECDH exchange computed. Session key: HKDF-SHA-512 with salt \u0026quot;Pair-Verify-Encrypt-Salt\u0026quot; and info \u0026quot;Pair-Verify-Encrypt-Info\u0026quot;. M2 decrypted: ChaCha20-Poly1305 with nonce \u0026quot;PV-Msg02\u0026quot; revealed TLV8 containing identifier 16F9D2EF-3E51-49C2-BD7B-2F145D422227 and a 64-byte Ed25519 signature. M3 sent: The server successfully decrypted M3 but rejected with Error=1 because the fabricated identifier was not in its paired peers list. The /pair-verify endpoint accepts requests with no rate limiting, though the final authorization check (peer identity lookup) prevents unauthorized session establishment.\nStep HKDF Salt HKDF Info Nonce Session key Pair-Verify-Encrypt-Salt Pair-Verify-Encrypt-Info - Signing key Pair-Verify-ECDH-Salt Pair-Verify-ECDH-Info - M2 decrypt - - \\x00\\x00\\x00\\x00PV-Msg02 M3 encrypt - - \\x00\\x00\\x00\\x00PV-Msg03 AirPlay transient pairing: establishing a session AirPlay 2 has two pairing families: HomeKit-based (SRP via /pair-setup) and legacy PIN (via /pair-pin-start). All prior testing targeted the HomeKit path.\nThe HomePod Mini in \u0026ldquo;Anyone on the Same Network\u0026rdquo; mode accepts transient pairing with PIN 3939. This is documented, intentional behavior for screenless AirPlay devices \u0026ndash; the pair_ap library and pyatv both document it. Screenless devices cannot display a dynamic PIN, so Apple uses a well-known static value. Anyone running Home Assistant connects to their HomePod this way daily.\nPOST /pair-pin-start → initiates PIN display (no-op on screenless HomePod) POST /pair-setup (state=1) → SRP M1, server returns M2 with salt + public key B POST /pair-setup (state=3) → SRP M3 with proof using PIN \u0026#34;3939\u0026#34; → server returns M4, authenticated session established POST /pair-verify → derives encrypted session keys All steps must occur on the same TCP socket. Session state is per-connection. Using separate HTTP requests fails because context is lost between connections. This is the standard mechanism for establishing an AirPlay session from a non-Apple device on the local network.\nSendVoiceInput crashes MRP data channel With the authenticated session, the HomePod exposes a Media Remote Protocol channel. Sending any MRP SendVoiceInput message (type 31), even empty, causes the data channel to terminate immediately.\nRoot cause: mediaremoted\u0026rsquo;s _handleVoiceDataReceivedMessage:fromClient: calls _MRVirtualVoiceInputProcessAudioData which requires an externalDevice context not initialized for AirPlay MRP tunnel connections. Null-reference bug in the device lookup path.\nTLV8 parser truncation The TLV8 parser returns HTTP 500 on truncated input:\nInput Result [type, 0x00] (length=0) HTTP 200 [type, 0x01] (length=1, no data) HTTP 500 [type, 0x01, data] (length=1, 1 byte) HTTP 200 Stable through 100+ consecutive requests. The exception is caught and does not cause memory corruption.\nFindings Finding Category Deterministic iBoot stack canary (0x4752440044003631) Bug (medium) SendVoiceInput crashes MRP data channel (null-reference in mediaremoted) Bug (medium) HTTP 500 on non-TLV8 input to /pair-verify (pre-auth) Bug (medium) HTTP 500 on invalid X-Apple-HKP header (pre-auth) Bug (low-medium) TLV8 parser HTTP 500 on truncated input Bug (low) AirPlay /pair-verify no rate limit on key exchange Observation AirPlay transient pairing with PIN 3939 By design (documented) OPACK binary protocol fully reversed Original research Complete A11 vs S5 iBoot architectural diff Original research Layer Surface Status iBoot USB DFU, command parser, Image4, LZFSE All hardened, closed Kernel 1,360 kexts, IOUserClients, WiFi driver Requires code exec first AirPlay :7000 /pair-setup, /pair-verify, /fp-setup Transient pairing via PIN 3939 (by design) Companion :49153 rapportd, OPACK, requires HomeKit trust Silent reject without trust RemotePairing :49152 OPACK protocol, TCP Needs prior pairing or BLE Lockdown :62078 Standard lockdown protocol Needs USB pairing Every remote vector is either PIN-gated, rate-limited, or requires an established trust relationship. The real bugs are in the post-auth path: the MRP null dereference and the pre-auth parser crashes.\nThe research is reproducible by anyone with a HomePod Mini, a Mac, and brew install libimobiledevice libirecovery.\nTools Tool Version Purpose libimobiledevice latest USB communication libirecovery latest Recovery mode interaction pyimg4 0.8.8 Image4 extraction and decryption radare2 6.1.0 Disassembly and binary analysis ipsw 3.1.664 IPSW download and firmware extraction ","permalink":"https://ahmetbirinci.dev/posts/homepod-mini-security-research/","summary":"\u003cp\u003eThe Apple HomePod Mini has never been jailbroken. The jailbreak community wrote it off after confirming its S5 chip (T8006) falls outside checkm8\u0026rsquo;s range (A5-A11 only). This writeup documents what I believe is the first publicly documented non-invasive security exploration of the HomePod Mini via its USB-C port, covering an interactive iBoot recovery shell session, full binary analysis of the firmware, and AirPlay protocol analysis on the running audioOS.\u003c/p\u003e\n\u003cp\u003eTarget: AudioAccessory5,1, Apple S5 (T8006), board b520ap, audioOS 26.3 (Build 23K620), iBoot-13822.80.422.0.2.\u003c/p\u003e","title":"security research on the HomePod Mini: from iBoot shell to AirPlay protocol analysis"}]