Back Cyberkendra WordPress libheif RCE Exploit Chain Goes Public
UK security firm Fortbridge on Monday published a working end-to-end exploit that turns an authenticated WordPress image upload into remote code execution by exploiting a critical heap overflow in libheif, the open-source library that decodes iPhone HEIC photos on servers.
The underlying flaw, tracked as GHSA-x8r2-mggj-j6wr , is a heap buffer overflow in libheif’s uncompressed-image (unci) decoder that the library’s maintainers rated critical. Wordfence researcher Alex Thomas found it on September 1 with the firm’s agentic testing framework, Argus , during a WordPress 7.1 assessment, and it was fixed in libheif 1.23.3. No CVE has been assigned yet. Fortbridge did not discover the bug; it built the public exploit chain that the original disclosure deliberately left unreleased.
The target is an ordinary WordPress install. An account with the upload_files capability — typically Author or higher — can upload a HEIC image via the standard Media Library. WordPress hands the file to PHP’s Imagick extension, which passes it to ImageMagick and then libheif, all inside a PHP-FPM worker running as the www-data account. Decoding occurs before any plugin or hardening rule inspects the file.
How does an image upload become code execution?
The flaw lives in libheif’s mixed-interleave YCbCr path. A crafted file declares the two chroma channels with different bit depths — Cb as 16-bit, Cr as 8-bit. libheif reserves one byte per sample for the Cr plane, but the shared chroma loop writes using Cb’s two-byte width, so each Cr write steps too far and carries attacker-controlled bytes past the end of the allocation.
Both the bytes written and the overflow length come from the file, which is what makes the bug a code-execution primitive rather than a simple crash. On a useful heap layout, the overflowing plane sits to libheif’s C++ channel vector or the decoder object itself.
Overwriting the decoder’s first machine word replaces its virtual-table pointer (vptr), the pointer a C++ object uses to locate its methods. When the decoder is torn down, it makes a virtual call, reads the attacker’s function address, and execution jumps wherever the exploit chooses. Fortbridge’s GDB output shows the decoder’s vptr filled with file bytes at the exact call site.
Controlling that jump is only half the problem. ASLR randomises where libc and ImageMagick are loaded each time a new PHP-FPM parent process starts, so the payload cannot hardcode the addresses it needs.
To recover live addresses, the exploit abuses a second libheif bug, GHSA-2jg2-4ch7-h545 , an out-of-bounds read in derived-item and plane handling patched in 1.23.2. A crafted image claims dimensions larger than its backing buffer; a later crop copies past the real allocation, dragging neighbouring heap bytes into the decoded output. WordPress then returns that output — inside the lossy JPEG thumbnail it generates for every upload.
Because the derivative is lossy, the leaked bytes cannot be read straight off. Fortbridge’s disclosure image moves the over-read data into the luma channel and expands each source byte into a uniform 8-by-8 block so the value survives JPEG compression; the exploit takes the median of each block and rebuilds the raw bytes.
It validates complete 64-bit pointer relationships rather than trusting anything that merely looks like an address, resolves the libc and MagickCore bases, and uses exact library-pointer pairs to fingerprint which tested build is running. The recovered profile data in the write-up shows it settling on one specific native stack and one page-aligned libc base.
A scheduling trick ties the pieces together. Apache will not reliably hand an attacker the same PHP-FPM worker twice, so the exploit sends seven slow HEIC uploads to occupy seven of the pool’s eight children and reserves the last for address recovery, heap calibration, and the trigger. Every child of one parent process shares the same library layout, so leaked bases remain valid until that parent is recycled.
How reliable is the exploit?
Fortbridge built and measured two exact profiles: Ubuntu 26.04 (WordPress 7.1.1, PHP-FPM 8.5.4, ImageMagick 7.1.2.18, libheif 1.21.2, glibc 2.43) and Debian 13 (WordPress 7.0, PHP-FPM 8.4.24, ImageMagick 7.1.1.43, libheif 1.19.8, glibc 2.41), both on amd64. Each takes a different control-flow route: Ubuntu points the hijacked vptr at a do_system call site inside libc, while Debian writes a fake virtual table into a writable region of ImageMagick’s MagickCore that RELRO leaves unprotected.
Across fresh PHP-FPM parent processes, the Ubuntu profile produced code execution in 6 of 8 (75 percent), and the Debian profile in 22 of 24 (91.7 percent). The researchers are strict what counts. A crashed worker returning HTTP 503 is not proof; the exploit confirms success only when a separate GET of a previously absent path returns 200 carrying the output of id — uid=33(www-data). “A 503 alone is crash telemetry, never RCE proof,” the researchers wrote.
Those rates hold only for the two measured stacks. Heap placement depends on process state, pool size, and live traffic, and any package update can shift the offsets and object layouts the profiles depend on, so a different build needs a fresh profile. Fortbridge released the exploit, payload generators, build profiles, and reproducible Ubuntu and Debian containers, calling it the first public exploit chain for this issue with a complete, remotely calibrated path.
The fix is to patch libheif: version 1.23.3 or later closes the overflow, and Debian has shipped 1.23.4-1~deb13u1 for its stable branch. Where HEIC and AVIF uploads are not needed, Fortbridge recommends rejecting them before native decoding or building libheif without the uncompressed codec. It also advises decoding untrusted media in an isolated, least-privileged service, treating repeated FPM child crashes and 503s around unci or crop-related uploads as security events, and blocking script execution from upload directories to limit what a successful overflow can reach.
The flaw lands amid a heavy run of WordPress code-execution issues, weeks after core patched the no-login file-inclusion bug CVE-2026-87902 in version 7.1.2.
Join the conversation. Ask questions, solutions, and help others.
Be the first to start the discussion!
The full story
This article is one source in a clustered incident — the cluster page carries the summary, timeline and every other outlet covering it.
