Skip to content

Security1 publisher2 min readPublished

libheif 1.23.5 blocks a 351-byte AVIF that forced allocations of more than 10 GB

libheif v1.23.5 fixes a high-rated flaw that let a 351-byte AVIF file force decoder allocations of more than 10 GB. It is a drop-in replacement for v1.23.4 and also closes six lower-rated memory-handling bugs.

The Watch · Security desk

Illustration accompanying libheif 1.23.5 blocks a 351-byte AVIF that forced allocations of more than 10 GB

What happened

  • libheif's maintainers shipped v1.23.5 with one high-rated security fix and advised all users to upgrade.
  • The flaw let a crafted image declare a small size in its ispe property while its bitstream coded a much larger frame, and the decoder allocated memory for the larger one.
  • Against the libaom AV1 backend, a 351-byte AVIF declaring 64x64 but coding up to 27648x27648 drove allocations from hundreds of MB to more than 10 GB.
  • The maintainers say the same class of flaw affects every codec whose real frame size is carried in the bitstream.

Compiled by The WatchSomething wrong?How this is made

Why it matters

  • exposure Anyone who can get an image decoded by a service running unpatched libheif can make a worker request gigabytes of memory with a 351-byte upload.
  • constraint On unpatched builds, an application's own max_image_size_pixels setting does not stop the file, so the worker's memory ceiling decides whether it survives.
  • decision Patch tracking keyed to CVE numbers has nothing to match yet. GHSA-v8qw-hwjv-44hw is the identifier available now, and waiting for the CVE leaves a drop-in fix uninstalled.

Before this release, max_image_size_pixels was checked against the size the container declared [4][7]. A service with a tight pixel ceiling checked the file's claimed 64x64 and let it through [5]. The decoder was then asked to hold a 764,411,904-pixel frame, 186,624 times the declared area [8].

v1.23.5 moves the check. The coded size is read from the bitstream and tested against max_image_size_pixels in the codec-independent decode path, before any bytes reach a decoder plugin [7]. The scan covers all AV1 sequence headers, all HEVC, AVC and VVC SPS NAL units, the JPEG SOF marker and the JPEG 2000 SIZ reference grid [7]. For the video codecs it also reads SPS units carried in the item data, beyond the ones in the configuration record [7]. The published proof only exercised AV1 through libaom [5].

Exploitation takes one upload. The attacker needs a way to get an image decoded by a service built on libheif, plus a 351-byte file [5]. The advisory describes memory exhaustion, which means denial of service [4]. Whether a given worker dies depends on its memory limit. In the demonstration, allocations ran from hundreds of MB to more than 10 GB [5]. The release notes do not mention exploitation [16].

Three medium fixes affect the same upload pipelines. A 3 KB JPEG 2000 file built from nested pclr boxes declaring zero palette columns reached about 330 MB of resident memory, none of it charged to max_total_memory [10]. Encoding an image that carries a TAI timestamp, including transcoding a file with an itai property, triggered a heap use-after-free and double free [9]. Services that re-encode uploads reach that code [9]. The third is an out-of-bounds read in alpha compositing for uncompressed images whose colour planes have different bit depths, and the stray heap bytes ended up in the composited output [11]. A service that returns processed images to the uploader would be sending those bytes back [11].

The low-rated items are narrower. Against OpenJPEG 2.3.1, the plugin bug produced a heap-buffer-overflow write; OpenJPEG 2.5.4 rejects the input [12]. The uncompressed-encoder read is reachable only through the public API, and decoding never produces the image that triggers it [14]. Parsing of the mini box ignored caller-set limits, but allocations were bounded by the bytes present in the box, so memory use could not be amplified [13].

What to watch

  • The CVE assignment for GHSA-v8qw-hwjv-44hw; scanners keyed to CVEs start flagging unpatched libheif builds from that point.
  • A public copy of the 351-byte AVIF, or any report of it being sent to upload endpoints.
  • Demonstrations of the same size mismatch against HEVC, AVC, VVC or JPEG decoder plugins, the other codecs the maintainers place in the class.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories