Pillow: Arrow export leaks stale heap memory when PILLOW_ALIGNMENT > 1
What fixes it
A fixed version on one release line is not the upgrade target for every line. Check your exact version and any vendor backports.
Description
Summary
When [PILLOW_ALIGNMENT](https://pillow.readthedocs.io/en/stable/reference/block_allocator.html#memory-pools) is set above 1, exporting an image to Arrow returns uninitialized heap memory mixed in with the pixel data. That memory can include pixels from images the process freed earlier.
Details
With an alignment above 1, the default allocator pads each row up to aligned_linesize and starts the first row at an aligned offset into the block. It then exports im->blocks[0].ptr as xsize * ysize tightly packed pixels, so exported data includes the padding bytes, and can include a few bytes from before the first row.
Tested vulnerable on 11.2.1, 12.3.0, 4c1ed27a5.
PoC
Whether things leak may depend on allocator configuration. This does show a leak on my Mac.
import os
os.environ["PILLOW_ALIGNMENT"] = "64"
from PIL import Image
# Image A: 64 px wide, so its rows fill the whole aligned stride
a = Image.new("L", (64, 40), 0x41).transpose(Image.Transpose.FLIP_LEFT_RIGHT)
del a
# Image B: 61 px wide, so each row has 3 bytes of padding; its pixels are all 0
b = Image.new("L", (61, 40), 0).transpose(Image.Transpose.FLIP_LEFT_RIGHT)
try:
exported = Image.fromarrow(b, b.mode, b.size).tobytes()
except ValueError as e:
print("Not vulnerable:", e)
else:
if leaked := len(exported) - exported.count(0):
raise RuntimeError(f"{leaked} of {len(exported)} exported bytes are not B's pixels")Impact
Information disclosure for applications that set PILLOW_ALIGNMENT and export images to Arrow. Likely any image whose row length isn't a multiple of the alignment will do. In a service handling several users' images, one user's exported data can contain pixels from another user's image, or other stale heap contents.
Text from GitHub Advisory Database
Affected versions 11
- Pillow, pip>= 11.2.1, < 13.0.0GitHub
- Pillowaffected: >= 11.2.1, < 13.0.0CVE List
- Pillow, pip11.2.1 - 13.0.0GitHub
- pillow, PyPIfrom 11.2.1, fixed in 13.0.0OSV
- pillow, PyPI11.2.1OSV
- pillow, PyPI11.3.0OSV
- pillow, PyPI12.0.0OSV
- pillow, PyPI12.1.0OSV
- pillow, PyPI12.1.1OSV
- pillow, PyPI12.2.0OSV
- pillow, PyPI12.3.0OSV
References 6
- github.com/python-pillow/Pillow/commit/19f64946eb247b973dd4560be7dea3bf979d2e6aFixvia CVE List
- github.com/python-pillow/Pillow/releases/tag/13.0.0Fixvia CVE List
- github.com/python-pillow/Pillow/security/advisories/GHSA-654x-cwwv-5j9cAdvisoryvia CVE List
- github.com/advisories/GHSA-654x-cwwv-5j9cAdvisoryvia GitHub
- nvd.nist.gov/vuln/detail/CVE-2026-114501Referencevia GitHub
- github.com/python-pillow/Pillow/pull/10172Referencevia CVE List