---
id: 2026-09-libheif-unci-mixed-interleave-heap-overflow-cve-2026-120208-sharp-bundle-not-compiled
title: "libheif 1.18.0 to 1.23.2 heap overflow in the unci decoder (CVE-2026-120208); sharp 0.34.3 and later never compiled that decoder"
date_disclosed: 2026-09-01
last_updated: 2026-11-01
severity: high
status: patched
ecosystems: [c, npm, nextjs, php, wordpress]
tools_affected: ["libheif 1.18.0 through 1.23.2 built with WITH_UNCOMPRESSED_CODEC=ON (default OFF); sharp 0.34.3 to 0.35.4 bundle libheif 1.20.1 to 1.23.2 without that codec; sharp 0.35.5 bundles 1.23.5"]
tags: [cve, libheif, heif, avif, image-parsing, heap-overflow, sharp, nextjs, next-image, wordpress, vulncheck, memory-safety]
---

## TL;DR

libheif's advisory GHSA-x8r2-mggj-j6wr (2026-09-01, vendor-rated Critical 9.8) is a heap buffer overflow in the `unci` uncompressed-image decoder: a HEIF file that declares unequal bit depths for its Cb and Cr planes makes the mixed-interleave path write past the smaller plane; fixed in 1.23.3 the same day, and VulnCheck issued CVE-2026-120208 for it on 2026-10-31 at 7.7. The decoder only exists when libheif is built with `WITH_UNCOMPRESSED_CODEC=ON`, which libheif leaves off by default and which sharp-libvips' build script does not set in any of the tags read (v1.2.0 to v1.3.3, under sharp 0.34.3 to 0.35.4), so `next/image`, Astro and other sharp users on 0.34.3 or later were not exposed to this one even on sharp 0.35.4; sharp 0.34.2 and older were not checked; anyone who builds libheif themselves with the uncompressed codec, or runs a distribution package that does, needs 1.23.3 or later.

## What happened

- **2026-09-01.** libheif maintainer farindk publishes GHSA-x8r2-mggj-j6wr, "Heap buffer overflow in `unci` mixed-interleave decoding with unequal chroma bit depths", Critical, CVSS 3.1 9.8 (`AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H`), CWE-787, affected >= 1.18.0 and <= 1.23.2, patched 1.23.3, credits alextwordfence and poppo25-Toss. The mixed-interleave YCbCr path "permits paired Cb and Cr components to have different bit depths"; each chroma plane is allocated by its own depth but both are written using the first chroma entry's byte width, so the smaller plane is written past its end. The reporter reproduced it with AddressSanitizer on the 1.23.2 release. The advisory states the bug is internal to libheif and requires `WITH_UNCOMPRESSED_CODEC=ON`; it says file disclosure and code execution were demonstrated on one specific WordPress deployment and that this "does not show universal RCE". The page prints "No known CVE" as read on 2026-11-01 and names a related advisory, GHSA-2jg2-4ch7-h545, which it says is distinct.
- **2026-09-01.** Release v1.23.3, "security release", ABI- and API-compatible with 1.23.2; the notes rate one fix critical, list several heap overflows and out-of-bounds reads, and describe tighter checks in the uncompressed decoder and in pixel-plane allocation.
- **2026-10-31, 17:25 UTC.** VulnCheck publishes CVE-2026-120208, "libheif 1.18.0 before 1.23.3 Heap Buffer Overflow via unci Mixed-Interleave Decoder", CVSS 4.0 7.7 (`AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N`) and CVSS 3.1 7.5 (`AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H`), affected `strukturag/libheif` 1.18.0 before 1.23.3, references the vendor advisory, fix commit 9d3cd91d, the v1.23.3 release and the source line in `unc_decoder_mixed_interleave.cc` at v1.23.2.

Two scores, two readings. The vendor's 9.8 is the worst case for a process that decodes attacker files with the codec compiled in; VulnCheck's 7.7 adds attack prerequisites and user interaction. Neither is a measurement of a given deployment, and the vendor's own page limits the demonstrated code execution to one deployment. This file's `severity` is high: real memory corruption in a parser that takes attacker bytes, gated by a non-default build flag.

**What sharp and Next.js users actually run.** sharp ships libheif inside its `@img/sharp-libvips-*` packages, and that project records the libheif version in `versions.properties` per release: sharp-libvips 1.2.0 and 1.2.1 carry libheif 1.20.1, 1.2.2 and 1.2.3 carry 1.20.2, 1.3.0 and 1.3.1 carry 1.23.0, 1.3.2 carries 1.23.1, 1.3.3 (npm 2026-08-26) carries 1.23.2, and 1.3.4 (npm 2026-09-27) carries 1.23.5. The sharp pins: 0.34.3 (2025-07-10) → 1.2.0, 0.34.4 → 1.2.3, 0.35.0 and 0.35.1 → 1.3.0, 0.35.2 → 1.3.1, 0.35.3 → 1.3.2, 0.35.4 (2026-08-26) → 1.3.3, 0.35.5 (2026-09-27) → 1.3.4. So every sharp release from 0.34.3 to 0.35.4 bundled a libheif version inside the affected range; sharp 0.34.0 to 0.34.2 pin sharp-libvips 1.1.0, whose tags carry no `versions.properties`, so their libheif version was not read this run. The build script, `build/posix.sh`, at sharp-libvips v1.2.0, v1.2.3 and v1.3.3 alike configures libheif with `-DBUILD_SHARED_LIBS=FALSE -DBUILD_DOCUMENTATION=0 -DBUILD_TESTING=0 -DENABLE_PLUGIN_LOADING=0 -DWITH_EXAMPLES=0 -DWITH_LIBDE265=0 -DWITH_X265=0` and does not set `WITH_UNCOMPRESSED_CODEC`; libheif's `CMakeLists.txt` at v1.23.2 declares that option "(experimental)" with default `OFF`. The vulnerable decoder is therefore not compiled into sharp's libheif, and this bug does not reach `next/image`, Astro's image service or any other sharp consumer through the bundled binaries. Separately, Next.js 15.5.24 and 16.3.3 (2026-08-25) disabled AVIF optimization after the earlier libheif advisory GHSA-g89c-p67h-r497, filed in [Next.js July and August 2026 releases](2026-07-nextjs-july-security-release.md), and `next@16.4.3` pins `sharp` at `^0.35.5`. Upgrading sharp to 0.35.5 still moves you to libheif 1.23.5 and is the right move for the other fixes in 1.23.3.

Why it is here: libheif is the HEIF and AVIF decoder under sharp, under `next/image`, and under the PHP and WordPress image stacks, and the last libheif critical did reach Next.js. This one does not reach the npm path, and a reader should be able to see why rather than take an aggregator's "libheif critical" at face value.

## Am I affected?

- **sharp, Next.js, Astro and other npm consumers:** not through the bundled libheif, for the build-flag reason above. Still check the version and move to the current line:

```bash
npm ls sharp @img/sharp-libvips-linux-x64 @img/sharp-libvips-darwin-arm64 2>/dev/null
```

  `@img/sharp-libvips-*` 1.3.4 means libheif 1.23.5; 1.2.0 to 1.3.3 means an affected libheif version with the vulnerable decoder not compiled; 1.1.x and older were not checked here.
- **Python wheels that bundle libheif** (`pillow-heif` and similar): not covered by this file. Whether those wheels enable the uncompressed codec was not read this run; check the wheel's bundled libheif version and build options before concluding either way.
- **Self-built or distribution libheif** (PHP `imagick` and `gd` through ImageMagick or libvips, WordPress hosts, GStreamer and desktop image viewers): check the installed version and whether it was built with the uncompressed codec:

```bash
heif-info --version 2>/dev/null; pkg-config --modversion libheif 2>/dev/null
```

  A version from 1.18.0 to 1.23.2 is affected if the build enabled `WITH_UNCOMPRESSED_CODEC`; the advisory's one demonstrated code-execution case was a WordPress deployment. If you cannot tell how the library was built, treat it as affected and upgrade.
- Scanners keyed on CVE ids will start flagging libheif < 1.23.3 from 2026-10-31, two months after the fix; a flag on a sharp-bundled copy is a true version match and a false exposure for this id.

## If you are affected

1. Upgrade libheif to 1.23.3 or later (1.23.5 is what sharp 0.35.5 bundles), or rebuild without `WITH_UNCOMPRESSED_CODEC` if you do not need uncompressed HEIF.
2. If a service decoded untrusted HEIF with an affected build, follow [if your web app was compromised](../playbooks/if-your-webapp-was-compromised.md) and review the host, since the vendor describes code execution as demonstrated.

## Prevention

- Keep image parsing off the host that holds secrets: run `next/image`, thumbnailers and upload processors on the Edge runtime or in an isolated service. See [supply-chain attack surface](../prevention/supply-chain-attack-surface.md).
- Do not pin `sharp` below the current line; the bundled libheif moves only when sharp does.

## Sources

- [libheif — GHSA-x8r2-mggj-j6wr: Heap buffer overflow in unci mixed-interleave decoding with unequal chroma bit depths](https://github.com/strukturag/libheif/security/advisories/GHSA-x8r2-mggj-j6wr) — fetched 2026-11-01: published 2026-09-01 by farindk, Critical 9.8 with vector, CWE-787, affected >= 1.18.0 <= 1.23.2, patched 1.23.3, the mechanism summary, the `WITH_UNCOMPRESSED_CODEC=ON` condition, the single-deployment RCE statement, credits, "No known CVE", the related-advisory note.
- [libheif — release v1.23.3](https://github.com/strukturag/libheif/releases/tag/v1.23.3) — fetched 2026-11-01: "security release", 01 Sep, ABI and API compatible with 1.23.2, one fix rated critical, hardening in the uncompressed decoder and plane allocation.
- [CVE Services — CVE-2026-120208](https://cveawg.mitre.org/api/cve/CVE-2026-120208) — queried 2026-11-01: VulnCheck CNA, published 2026-10-31 17:25 UTC, title, description, affected range, both CVSS metrics, references including commit 9d3cd91d and the v1.23.2 source line.
- [sharp-libvips — versions.properties at v1.2.0, v1.2.1, v1.2.2, v1.2.3, v1.3.0, v1.3.1, v1.3.2, v1.3.3 and v1.3.4](https://raw.githubusercontent.com/lovell/sharp-libvips/v1.3.4/versions.properties) — fetched 2026-11-01: `VERSION_HEIF` 1.20.1, 1.20.1, 1.20.2, 1.20.2, 1.23.0, 1.23.0, 1.23.1, 1.23.2 and 1.23.5 respectively; the v1.1.0 and v1.1.1 tags return no such file.
- [sharp-libvips — build/posix.sh at v1.3.3](https://raw.githubusercontent.com/lovell/sharp-libvips/v1.3.3/build/posix.sh), and the same file at [v1.2.0](https://raw.githubusercontent.com/lovell/sharp-libvips/v1.2.0/build/posix.sh) and [v1.2.3](https://raw.githubusercontent.com/lovell/sharp-libvips/v1.2.3/build/posix.sh) — fetched 2026-11-01: the libheif cmake invocation quoted above in each, with no `WITH_UNCOMPRESSED_CODEC` setting.
- [libheif — CMakeLists.txt at v1.23.2](https://raw.githubusercontent.com/strukturag/libheif/v1.23.2/CMakeLists.txt) — fetched 2026-11-01: `option(WITH_UNCOMPRESSED_CODEC ... (experimental) OFF)`.
- npm registry, queried 2026-11-01: `@img/sharp-libvips-linux-x64` `time` (1.3.3 2026-08-26, 1.3.4 2026-09-27); `sharp` `time` (0.35.4 2026-08-26, 0.35.5 2026-09-27); `sharp@0.34.0` through `sharp@0.35.5` `optionalDependencies.@img/sharp-libvips-linux-x64` (1.1.0, 1.1.0, 1.1.0, 1.2.0, 1.2.3, 1.3.0, 1.3.0, 1.3.1, 1.3.2, 1.3.3, 1.3.4) and `sharp` `time` for 0.34.3 (2025-07-10) and 0.34.4 (2025-09-17); `next@16.4.3` `optionalDependencies.sharp` `^0.35.5`.
