PoC Archive PoC Archive
High CVE-2026-20687 patched

AppleJPEGDriver startDecoder Timeout Use-After-Free (CVE-2026-20687)

by Enfilade (enfilade.io / enfilade-labs) · 2026-07-05

Severity
High
CVE
CVE-2026-20687
Category
binary
Affected product
AppleJPEGDriver kernel extension
Affected versions
iOS/iPadOS 26.3 (tested on iPhone 18,2 / iPhone 17 Pro Max, A19 Pro); fixed in iOS/iPadOS 26.4
Disclosed
2026-07-05
Patch status
patched

Metadata

FieldValue
Date Added2026-07-05
Last Updated2026-04
Author / ResearcherEnfilade (enfilade.io / enfilade-labs)
CVE / AdvisoryCVE-2026-20687
Categorybinary
SeverityHigh
CVSS ScoreNot specified in source
StatusPoC
Tagsios, kernel, applejpegdriver, use-after-free, mte, iokit, kernel-panic, camera
RelatedN/A

Affected Target

FieldValue
Software / SystemAppleJPEGDriver kernel extension
Versions AffectediOS/iPadOS 26.3 (tested on iPhone 18,2 / iPhone 17 Pro Max, A19 Pro); fixed in iOS/iPadOS 26.4
Language / PlatformObjective-C, IOKit userspace client calling into a kernel JPEG decode driver
Authentication RequiredNo
Network Access RequiredNo (local app, physical device required)

Summary

AppleJPEGDriver’s synchronous decode path (startDecoder_sync) can time out while a decode request is still referenced by a per-codec queue-node vector; on timeout the driver frees the request object but fails to remove its embedded queue-node pointer from that vector, leaving a dangling reference. A later queue walk (finish_io_gated / fullSpeedRequestExist) dereferences the stale node, triggering a use-after-free that is caught by ARM Memory Tagging Extension (MTE) enforcement and panics the kernel. The PoC primes the driver with a burst of asynchronous decode requests and closes the connection to induce the timeout condition; the panic itself is typically deferred until the next synchronous JPEG decode occurs, which on iPhone reliably happens when the Camera app is opened.


Vulnerability Details

Root Cause

The timeout-handling path in startDecoder_sync frees a decode request object without dequeuing its embedded node pointer from the per-codec queue vector, leaving a stale/dangling reference that is later dereferenced.

Attack Vector

  1. Open the AppleJPEGDriver IOKit service from an unprivileged app.
  2. Issue a burst of asynchronous startDecoder_async calls, each of which pushes a queue node (req + 0x78) onto the driver’s per-codec vector.
  3. Close the connection (IOServiceClose), leaving queued state behind.
  4. At some later point a synchronous decode (startDecoder_sync) times out (~10s) waiting on the queue and frees the associated request — but does not remove its stale node pointer from the vector.
  5. The next queue walk (triggered, in practice, by opening the Camera app, which performs its own synchronous JPEG decode) dereferences the stale node pointer, reading from freed memory and tripping an MTE tag-check fault that panics the kernel.

Impact

Reliable local denial of service (kernel panic / device reboot) triggerable by an unprivileged local app, with a deferred trigger condition (opening Camera) that can make the crash appear unrelated to the initiating app; the underlying use-after-free is also a plausible kernel memory-corruption primitive.


Environment / Lab Setup

Target:   iOS/iPadOS 26.3 on a physical device (e.g. iPhone 17 Pro Max, A19 Pro)
Attacker: Xcode, ability to build and run a native Objective-C IOKit-calling app on the physical device

Proof of Concept

PoC Script

See ViewController.m in this folder — the on-device trigger logic meant to be built as part of an Xcode iOS app target.

The button handler opens AppleJPEGDriver, issues a burst of asynchronous decode requests to populate the stale queue-node vector, then closes the connection; opening Camera afterward performs a synchronous decode that walks the corrupted queue and panics.


Detection & Indicators of Compromise

Signs of compromise:

  • Kernel panic logs showing an MTE tag-check fault inside JPEG decode / queue-walk code paths (finish_io_gated, fullSpeedRequestExist).
  • Panics that appear correlated with opening Camera shortly after running a third-party app with no obvious camera/JPEG functionality.
  • Repeated IOServiceOpen/startDecoder_async bursts against AppleJPEGDriver from an unprivileged process.

Remediation

ActionDetail
Primary fixUpdate to iOS 26.4 / iPadOS 26.4 or later, which Apple states addresses this use-after-free with improved memory management
Interim mitigationAvoid running untrusted third-party apps on affected builds; monitor for apps making unusual IOKit calls to AppleJPEGDriver

References


Notes

Mirrored from https://github.com/enfilade-labs/CVE-2026-20687-AppleJPEGDriver-UAF on 2026-07-05.