CVE-2026-112405: Pillow: NULL pointer dereference in Image.merge via an unvalidated band 0
Summary Image.merge() checks the mode of every input band except band 0. If band 0 is a single-band I or F image, the native merge routine reads a pixel pointer that is NULL for those modes and the process crashes. The IPTC plugin reaches this from a plain Image.open() followed by a load, and IPTC has no magic-byte prefilter, so a crafted file with no recognizable header can drive it.
Details The validation loop skips band 0:
- src/PIL/Image.py:3795 iterates for band in bands[1:] and checks mode and size only for those.
For an I or F image the 8-bit plane image8 is NULL (only image32 is set). ImagingMerge dereferences bands[0]->image8[y] for the multi-band output modes:
- src/libImaging/Bands.c:302, :311, :321
The IPTC loader builds the band list from an attacker-typed sub-image and passes it to merge with the sub-image at index 0:
- src/PIL/IptcImagePlugin.py:156-160 - src/PIL/IptcImagePlugin.py:169 registers the opener with no accept function.
PoC python from PIL import Image
Band 0 is a single-band "I" image: its image8 plane is NULL. merge() validates only bands[1:], so the native ImagingMerge dereferences the NULL plane for band 0. band0 = Image.new("I", (4, 4)) Image.merge("RGB", [band0, Image.new("L", (4, 4)), Image.new("L", (4, 4))])
Run it: $ python 02poc.py Segmentation fault (core dumped)
Observed on a source build of commit 3e2ab96.
Under AddressSanitizer: ==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 #0 ImagingMerge src/libImaging/Bands.c:311 #1 merge src/imaging.c:2492 SUMMARY: AddressSanitizer: SEGV src/libImaging/Bands.c:311 in ImagingMerge The null address confirms the dereference of the missing image8 plane for band 0.
Impact NULL pointer dereference in a C extension. A crafted file opened and loaded through the IPTC path crashes the worker process. This is a hard crash, not a Python exception an application can catch.
Other sources
Pillow is a Python imaging library. From 12.0.0 until 13.0.0, Pillow's Image.merge() can dereference a null image8 plane. Validation skips the first input band, allowing a 32-bit integer or floating-point image backed by image32 storage to be merged as a narrower multiband image. A crafted IPTC file can reach this path when an application opens and loads it, or a caller can invoke Image.merge() directly with such a first band. This causes a native process crash. This issue is fixed in version 13.0.0.
— NVD
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
pip/pillowto a version that resolves this vulnerability.Fixed in 13.0.0 - Upgrade
Upgrade
bitnami/pillowto a version that resolves this vulnerability.Fixed in 13.0.0 - Upgrade
Upgrade
Pillowto a version that resolves this vulnerability.Fixed in 13.0.0
Event History
Frequently Asked Questions
Which deployments are exposed to attacker-controlled input?
Applications using Pillow 12.0.0 through versions before 13.0.0 are exposed if they open and load crafted IPTC files. The issue can also be triggered by application code that directly calls Image.merge() with a maliciously constructed first band.
What is the practical impact of successful exploitation?
Successful exploitation causes a NULL pointer dereference in native code, resulting in a process crash. The provided CVSS vector indicates availability impact only, with no stated confidentiality or integrity impact.
Does exploitation require authentication or user interaction?
No. The supplied CVSS vector indicates network reachability, low attack complexity, no privileges required, and no user interaction; however, the affected application must process the crafted IPTC file or invoke the vulnerable Image.merge() path.
What version resolves the issue?
Upgrade Pillow to version 13.0.0, which fixes the issue. The affected range begins at 12.0.0 and ends before 13.0.0.