An array index became a pointer.
Selector 95 omitted a bound enforced by its sibling. An out-of-range slot could reinterpret adjacent provider state as an object pointer. The investigation progressed from register control to a kernel-load witness, with each claim tied to a separate experiment.
During the iOS beta cycle, I compared new kernel functionality with neighbouring operations. Selector 95 in IOMobileFramebufferUserClient used the same provider array as selector 93, but the two paths disagreed about index validation. [E1]
The tested entry point was reachable from an ordinary development-signed app through connection type 0. Its dispatch contract accepted one scalar and a 20-byte structure, with no outputs and no private entitlement requirement. The experiment was performed on a physical iPhone14,4 / D16AP, running iOS 27 beta 4, build 24A5390f.
The intended array has 189 entries. A valid index must satisfy (uint32_t)index < 0xbd. The adjacent selector 93 enforced that condition before computing a slot; selector 95 did not. [E1]
010xfffffff009a868d8 cmp w2, #0xbc020xfffffff009a868dc b.hi 0xfffffff009a8699cThe general slot computation also includes signed-low-32-bit and pointer-poisoning behaviour. For the small index used in the read demonstration, the relevant arithmetic simplifies to:
01array_base = provider + 0x174002slot = array_base + 0xd4 * 0x3803 = provider + 0x45a004slot + 0x18 = provider + 0x45b8The out-of-range slot overlaps provider state populated by a legitimate transaction. The bug is the unchecked reinterpretation of that state as an array element. SwapDebugInfo is a value carrier here, not a second vulnerability. [E2]
transaction + 0x48slot + 0x18ldr x16, [x0]The app reads the current-boot Target Address dynamically. A legitimate transaction carries that qword into provider state.
Read the complete value flow
- The app captures the current-boot Target Address with three equal, nonzero reads.
- SwapDebugInfo places it at transaction +0x48; selector 5 submits the transaction.
- The DCP path copies transaction +0x40..+0x4f into swap-node +0xc40..+0xc4f.
- Layer-2 completion copies node +0xc48 into provider +0x45b8.
- Index 0xd4 selects provider +0x45a0. The stored qword is now interpreted as slot +0x18.
- The helper loads that qword into x0 and executes ldr x16, [x0].
The original report demonstrated full 64-bit register control. The helper loaded the app’s qword into x0, then faulted on an out-of-bounds access without overwriting it. That established a register primitive; it did not yet establish a selected-address kernel read. [E1]
010xfffffff009a866a4 ldur x0, [x3, #0xc]020xfffffff009a866a8 cbz x0, 0xfffffff009a867f0030xfffffff009a866ac mov w21, #0040xfffffff009a866b0 ldr w9, [x19, #0x28]The follow-up used the same missing check to reach a stronger, distinct witness: a kernel load from the current-boot Apple Target Address. It used _COMM_PAGE_ASB_TARGET_KERN_ADDRESS, rather than the Target Value used for register control. [E2]
010xfffffff009a867f4 x0 ← [slot + 0x18]02 …030xfffffff009a867fc ldr x16, [x0]| Check | Run 1 | Run 2 |
|---|---|---|
| Runtime target capture | Three matching reads | Three matching reads |
| Panic x0 and FAR | Match same-boot target | Match same-boot target |
| Index in x22 | 0xd4 | 0xd4 |
| Unslid PC | 0xfffffff009a867fc | 0xfffffff009a867fc |
| Recorded pair verification | 27 / 27 | 27 / 27 |
The retained supplement records 8/8 cross-run checks. Both runs used the same installed binary and different boot sessions. These are archived results, not fresh device runs performed for this article. Boot identifiers and raw panic files are not reproduced here. [E2]
What the evidence supports
- Ordinary-app reachability on the tested build.
- A missing index check and a native out-of-bounds operation.
- Full-width kernel register control in the original witness.
- A crash-based kernel-load demonstration satisfying the recorded Target-Flag read contract.
What it does not establish
- Kernel data returned to the application as a general readback oracle.
- An arbitrary-write primitive.
- Program-counter control or kernel code execution.
- The exact beta-4 mechanism on every affected Apple platform.
Apple’s public advisory describes an out-of-bounds access issue with potential system termination or kernel-memory corruption, addressed through improved bounds checking. Credit is shared with other researchers. [E3]
01if ((uint32_t)index >= 0xbd)02 return kIOReturnBadArgument;0304// Only then calculate and use the slot.- DISCOVERYA sibling comparison
Binary diffing narrowed the search; the inconsistent guard supplied the hypothesis.
- VALIDATIONRegister control, then a kernel-read witness
The second demonstration reused the original root cause and established a different primitive.
- DISCLOSUREReported to Apple
Technical reports and reproducible evidence were supplied through Apple Security.
- PUBLIC RECORDCVE-2026-65398
Apple lists shared credit and a bounds-checking remediation.
I directed target selection, hypothesis formation and validation. AI accelerated reverse analysis, PoC development and reporting. The conclusions came from the evidence. This chronology does not assert that Apple’s patch was created in response to my report.
The article separates retained research records from the vendor’s public acknowledgement. The downloadable excerpt contains the selected technical passages used here, not the complete original submission or a runnable exploit.
Original register-control report
Author’s retained APPLE_REPORT.md: dispatch contract, sibling check, register witness and proposed remediation.
Kernel-read supplement
Author’s retained TECHNICAL_NOTE.md: same-root-cause value flow, exact executed binary and cross-boot results.
Apple security advisory
Public CVE attribution and vendor impact description. The linked advisory is for macOS Golden Gate 27; the experiment in this article was on iOS beta 4.
Open source ↗A different path through the same boundary.
The AuthKit branch of a preference-access investigation.
Read the related investigation