CVE-2026-96638
mediumpriority · track · 0EPSS 0.004 · 28 %ileUSEPSS · scored 2026-10-27
Pillow is a Python imaging library. From 9.1.0 until 13.0.0, BmpRleDecoder.decode() in src/PIL/BmpImagePlugin.py permits crafted RLE BMP delta escapes and absolute-mode runs to append beyond the remaining dest_length without a per-branch cap. A delta can add roughly 255 image rows in one iteration, so a kilobyte-sized file with a large but permitted width can expand the data bytearray to hundreds of megabytes or more, causing memory-exhaustion denial of service. This issue is fixed in version 13.0.0.
cvss
Technical severity, 0–10. One row per scoring source.
base score 0–10 · higher = more severe · hover a vector to decode
weaknesses
The CWE weakness classes this flaw belongs to.
affected products (2)
Products and version ranges known to be affected.
advisories (1)
Vendor and ecosystem advisories describing this.
- GHSA-24rc-8hj2-v98cPillow: BMP RLE decoder memory-amplification DoS via unbounded delta escape / absolute mode2026-10-22ghsa · osvUS
## Summary BmpRleDecoder can be forced to allocate gigabytes of memory from a kilobyte-sized crafted BMP file via unbounded growth in the delta escape and absolute mode branches. ## Affected versions All versions up to and including current HEAD (v13.0.0.dev0, commit e7a7ea84) ## Root cause BmpRleDecoder.decode() (BmpImagePlugin.py:327-395) builds a Python bytearray `data` with dest_length = xsize*ysize, looping `while len(data) < dest_length`. The loop condition is only checked at the TOP; individual branches append attacker-controlled amounts UNBOUNDED by dest_length: - delta escape (line 370): data += b"\x00" * (right + up * self.state.xsize) with right,up in 0..255 -> up to ~255*xsize bytes in ONE iteration. - absolute mode (line 385): data += bytes_read (up to 255). Because a single delta can push len(data) to ~256 * (row size), a tiny RLE stream combined with a large-but-legal xsize (xsize*ysize just under MAX_IMAGE_PIXELS, ~89M) yields a multi-GB `data` bytearray (then copied again by bytes(data) and set_as_raw). No heap OOB (bytearray/set_as_raw are bounds-safe), but a severe memory-amplification DoS: the attacker file stays tiny. ## Reproduction Python 3.13, Pillow HEAD e7a7ea84 Attached: pillow_poc_bmp_rle_dos.py A 1084-byte BMP (BI_RLE8, width=3,000,000, height=1 -> 3M px, passes bomb check) with one delta escape (00 02 00 150) produces ~429 MB `data`; measured peak RSS 911 MB. Scaling width toward the bomb limit and up=255 produces tens of GB from a ~1 KB file. ## Suggested fix Cap growth at dest_length in the delta and absolute branches, e.g. clamp the delta fill to (dest_length - len(data)) and stop appending once len(data) >= dest_length; reject deltas that would move the cursor beyond the image, matching the existing per-row clamp at line 341-343. Credit: Yazan Balawneh - CyStack Security Team (GitHub: sonicnew) [pillow_poc_bmp_rle_dos.py](https://github.com/user-attachments/files/30244974/pillow_poc_bmp_rle_dos.py)
sources
Which sources assert this record, and when.
references (4) nvd
External citations — patches, advisories, analysis.
- https://github.com/python-pillow/Pillow/commit/e7794835e323ff2691d9b3a974cade1a44301b9aPatch
- https://github.com/python-pillow/Pillow/pull/10015Issue Tracking
- https://github.com/python-pillow/Pillow/releases/tag/13.0.0Release Notes
- https://github.com/python-pillow/Pillow/security/advisories/GHSA-24rc-8hj2-v98cVendor Advisory
Attackers weaponise vulnerabilities like this against internet-exposed services. See what is exposed on your perimeter with a free passive scan.
Free scan