← Back to research
Defense & recoveryRESEARCH · 7 MIN READ

A Bluetooth crash hiding behind checks that actually worked

Apple’s Bluetooth code recognized an unsuitable channel, returned a failed result and crashed when its caller used it anyway. My report shows how working checks, reassuring logs and a real service failure can all coexist.

A brushed-metal Bluetooth symbol stands within blue signal rings interrupted at an amber-lit channel junction.

My Mac’s Bluetooth service logged why it could not carry out a request, then crashed trying to carry it out anyway. The warning came from a validator that had correctly rejected the requested channel state. Its caller tried to use the missing state without checking the result. The diagnostic was accurate. It just did nothing to save the process.

I had made the test Mac available for incoming Bluetooth connections with a helper app; the incoming connection did not require a trusted pairing. The failure was especially revealing because other checks were working. Missing channels and malformed sizes could be rejected, and a neighboring handler could discard an inappropriate request without crashing. The code had several opportunities to behave sensibly, and evidence that it knew how.

Apple’s October 26, 2026 advisories credit Chris Bailey - Short Circuit in CVE-2026-112566, with no other researcher named in that entry. Apple describes a nearby attacker causing a denial of service through a null pointer dereference, addressed with improved validation. In ordinary language, the Bluetooth service tried to use information that was not there and stopped running.

Apple gives this identifier and CVE-2026-113906 the same short technical description. Its notices do not map my individual Mac and iPad submissions to one CVE or the other. This article examines the shared research and uses Apple’s published release coverage for CVE-2026-112566.

Apple’s Bluetooth entry for CVE-2026-112566

The channel existed. That was part of the problem.

A Bluetooth connection is not one undifferentiated stream of useful things. It contains logical channels that organize different kinds of work. Those channels have different capabilities, and some operations only apply to a particular kind. Finding a channel in the connection’s records tells the software that it exists. It does not establish that the channel supports everything a remote device might ask it to do.

My report separates those two decisions because the distinction explains the crash. The first lookup found a real channel. A later validator examined whether that channel had the state required for the requested operation. It did not. The validator returned a null pointer: an explicit absence of the object the caller would need to continue.

There is nothing inherently defective about returning null. A lookup or validation function needs some way to say that it cannot supply the requested object. The caller’s job is to treat that outcome as a failure and take an appropriate exit. Here, the caller performed a memory access through the returned value without checking it. The failure result had reached exactly the code that needed to respect it, and that code did not.

This also explains a result that can look confusing until you follow the whole path: a channel that was not present could be handled more safely than a real channel of the wrong kind. The nonexistent one failed the initial lookup and left the operation early. The existing one passed that stage and reached the later check whose failure was mishandled. Existence and suitability were separate conditions, even though the caller effectively treated them as interchangeable.

The tests that did not crash mattered

The unsuccessful tests helped narrow the cause. Other channel cases and randomized traffic did not bring the service down indiscriminately; the crash depended on reaching the relevant channel case. That matched the code: an absent channel could leave through a safe rejection, while an existing channel could reach the later validation whose failure the caller mishandled. The test results and the program were pointing at the same mistake.

The incoming data also passed through size checks, including a bounded copy into working storage. Those protections were present, so an oversized packet overrunning a buffer was the wrong explanation. The failure came later, when the caller used a rejected result. A stricter size check would have left that assumption exactly where it was.

The warning was real. So was the crash.

The Mac evidence included a log message from the validator rejecting the channel’s type before the service failed. That message matters, but it needs to be read alongside the code that emitted it. A warning can report a failed condition and then return control to the caller. It does not necessarily terminate the operation, and it certainly does not force every caller to handle the failure correctly.

That is what happened here. The validator reported the unsuitable channel and returned normally. The fatal access happened in its caller. The distinction rules out an easy misreading of the evidence: the service was not deliberately aborting inside the validator as its chosen response to invalid input. The validator had a failure result available; the caller attempted to use that result as though it described valid state.

The surrounding service already contained examples of better behavior. A neighboring handler encountered an invalid channel for its operation, logged the problem and dropped the request without crashing. I included that comparison in the report because it makes the expected outcome concrete. The software was perfectly capable of rejecting an inappropriate request and continuing to run. It just was not doing that consistently.

This is why I keep reading past the validation function. A reassuring name, a warning in the log and a branch that rejects some bad inputs can all exist in vulnerable code. What matters is whether the particular failed condition reaches an exit before the next operation relies on it. The caller is part of the check’s effectiveness, however much that complicates a tidy review checklist.

A service restart does not make the interruption imaginary

The Mac crash records came from separate service processes and agreed on the failing location and the surrounding call path. The evidence placed the failure in the handling of incoming Bluetooth traffic. The iPad submission documented the corresponding pattern in its own Bluetooth binary, with device crash records to support it. The compiled layouts differed; the unchecked use of the failed result did not.

On the Mac, the operating system restarted the crashed service. Recovery is good, and I would much rather have a service restart than stay dead. It does not change the fact that a nearby peer had caused the interruption. Software depending on that service still has to cope with the break and any reconnection work that follows. A restarted process is evidence of recovery, not evidence that nothing happened.

The demonstrated impact was denial of service: an invalid access through an absent object, with no demonstrated ability to replace program instructions, read private files or take over the machine. These runs do not establish that a default Mac was always exposed whenever Bluetooth was on. Apple’s entry does not report exploitation in the wild.

The crash location was not the only use to review

My report identified the same unchecked-result pattern at another use within the affected routine. The captured crash occurred at the first access, but stopping there would have left another instance of the assumption unexamined. I recommended ending the operation whenever the required state was unavailable and reviewing other callers of the validator. That recommendation did not establish that every caller was vulnerable.

Apple describes its correction as improved validation. I have not analyzed the shipped patch, so I cannot say whether it followed my proposed change. The existing neighboring handler supplied a concrete standard for the outcome: it rejected an unsuitable request and kept the service running.

The credit and the updates

Apple lists CVE-2026-112566 in the following releases. The links give Apple’s published fix coverage; my device testing was on Mac and iPad, rather than every product in this list.

The companion article concentrates on the iPad crash evidence and the connection conditions behind the mobile tests. It lists the two iPhone and iPad release branches in which Apple publishes CVE-2026-113906.

Read the iPad Bluetooth research and CVE-2026-113906 coverage

I am pleased to see Chris Bailey - Short Circuit named in the credit, and grateful to Apple’s security and engineering teams for addressing the issue. Install the supported update offered for each device you maintain and check that it completed.

All seven October Apple credits

Apple’s advisories checked October 26, 2026.

Published by Short Circuit LLC. Questions or corrections? Contact us