← All reports

[non-cocoa][fuzz] OOB read in APNG with hidden default image

Component: WebCore image decoders | 56c0a88

Animated PNG (APNG) extends PNG with a frame sequence, and a file may declare that its default image — the base PNG that non-APNG-aware decoders render — is not part of the animation. That distinction leaves the non-Cocoa decoder tracking two overlapping notions of "current frame" across libpng's row and end callbacks, and a crafted file with a hidden default image could desynchronize them.

This commit fixes a fuzz-found out-of-bounds read by simplifying how the decoder tracks libpng callback state, so the frame lifecycle no longer depends on reconciling those two views. The bug was reported publicly with no security classification.

This is the second fuzz-found memory-safety bug in the non-Cocoa image decoders this week, alongside the AVIF/WebP/JPEG XL out-of-bounds writes. Both reach untrusted content through an ordinary <img> decode on the GTK and WPE ports, and both come from frame-lifecycle bookkeeping rather than from the codec libraries themselves.

The forward-facing pattern is decoder state that lives across a codec library's callbacks rather than being owned outright by the decoder, so two views of "which frame am I on" can drift apart under crafted input. Narrow: the other non-Cocoa multi-frame decoders driven through library callbacks carry the same shape — check each for a frame index or frame pointer that one callback reads but only a different callback updates, and ask what a file that skips or reorders the expected callback sequence does to it. Wider: this is the same frame-lifecycle bookkeeping the AVIF/WebP/JPEG XL fixes touched from the other end, where the backing store's per-frame rect was being dropped on copy — audit the decoders and ImageBackingStore together for places where the frame the decoder believes it is writing and the frame the backing store describes are tracked separately. Widest: any format that lets a header declare a stored element to be outside the sequence it belongs to creates two counts that must stay aligned; the review tell is a callback handler that derives a frame position from a member the callback itself never writes.