{"schema":"threatline.record/2","record":{"id":"CVE-2026-96638","aliases":["GHSA-24rc-8hj2-v98c"],"summary":"Pillow: BMP RLE decoder memory-amplification DoS via unbounded delta escape / absolute mode","details":"## Summary\nBmpRleDecoder 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.\n\n## Affected versions\nAll versions up to and including current HEAD (v13.0.0.dev0, commit e7a7ea84)\n\n## Root cause\nBmpRleDecoder.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:\n\n- 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.\n- absolute mode (line 385): data += bytes_read (up to 255).\n\nBecause 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.\n\n## Reproduction\nPython 3.13, Pillow HEAD e7a7ea84\n\nAttached: pillow_poc_bmp_rle_dos.py\n\nA 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.\n\n## Suggested fix\nCap 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.\n\nCredit: Yazan Balawneh - CyStack Security Team (GitHub: sonicnew)\n\n[pillow_poc_bmp_rle_dos.py](https://github.com/user-attachments/files/30244974/pillow_poc_bmp_rle_dos.py)","categories":["Libraries & packages"],"product":"pillow","vendor":"python-pillow","ecosystem":"pip","affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-24rc-8hj2-v98c","source_modified_at":"2026-10-22T15:59:36Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"pip","name":"pillow"},"range":">= 9.1.0, < 13.0.0"},{"source":"CVE List","source_url":"https://www.cve.org/CVERecord?id=CVE-2026-96638","source_modified_at":"2026-10-21T20:47:21.767Z","fetched_at":"2026-10-23T18:42:43.628194Z","product":"Pillow","vendor":"python-pillow","versions":[{"status":"affected","version":">= 9.1.0, < 13.0.0"}],"defaultStatus":null},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-24rc-8hj2-v98c","source_modified_at":"2026-10-22T16:15:46.839620074Z","fetched_at":"2026-10-23T18:45:31.882637Z","package":{"name":"pillow","ecosystem":"PyPI","purl":"pkg:pypi/pillow"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"9.1.0"},{"fixed":"13.0.0"}]}],"versions":["10.0.0","10.0.1","10.1.0","10.2.0","10.3.0","10.4.0","11.0.0","11.1.0","11.2.1","11.3.0","12.0.0","12.1.0","12.1.1","12.2.0","12.3.0","9.1.0","9.1.1","9.2.0","9.3.0","9.4.0","9.5.0"]}],"fixed_versions":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-24rc-8hj2-v98c","source_modified_at":"2026-10-22T15:59:36Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"pip","name":"pillow"},"version":"13.0.0"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-24rc-8hj2-v98c","source_modified_at":"2026-10-22T16:15:46.839620074Z","fetched_at":"2026-10-23T18:45:31.882637Z","package":{"name":"pillow","ecosystem":"PyPI","purl":"pkg:pypi/pillow"},"version":"13.0.0"}],"cvss":6.5,"severity":"Medium","kev":{"listed":false},"epss":{"probability":0.0028,"percentile":0.19461,"score_date":"2026-10-23"},"published_at":"2026-10-21T20:47:21.767Z","modified_at":"2026-10-22T16:15:46.839620074Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/advisories/GHSA-24rc-8hj2-v98c","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-22T15:59:36Z"},{"source":"CVE List","url":"https://www.cve.org/CVERecord?id=CVE-2026-96638","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-21T20:47:21.767Z"},{"source":"OSV","url":"https://osv.dev/vulnerability/GHSA-24rc-8hj2-v98c","fetched_at":"2026-10-23T18:45:31.882637Z","source_modified_at":"2026-10-22T16:15:46.839620074Z"},{"source":"EPSS","url":"https://api.first.org/data/v1/epss?cve=CVE-2026-96638","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-23"}],"sources":["GitHub Advisory Database","CVE List","OSV","EPSS"],"references":[{"source":"CVE List","url":"https://github.com/python-pillow/Pillow/security/advisories/GHSA-24rc-8hj2-v98c","tags":["x_refsource_CONFIRM"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-96638","source":"GitHub Advisory Database"},{"source":"CVE List","url":"https://github.com/python-pillow/Pillow/pull/10015","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/python-pillow/Pillow/commit/e7794835e323ff2691d9b3a974cade1a44301b9a","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/python-pillow/Pillow/releases/tag/13.0.0","tags":["x_refsource_MISC"]},{"url":"https://github.com/advisories/GHSA-24rc-8hj2-v98c","source":"GitHub Advisory Database"}],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"cve_state":"PUBLISHED","classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":"product","confidence":"heuristic","reviewed":false},"change_timestamp":"2026-10-22T16:15:46.839620074Z","content_hash":"6ec14ad27a005e6f2554c0301d2c7737ba0267222cd21e026a2601fdf2ebeca3"}}
