{"id":"CVE-2026-114501","kind":"vulnerability","aliases":["CVE-2026-114501","GHSA-654x-cwwv-5j9c"],"related":[],"title":"Pillow: Arrow export leaks stale heap memory when PILLOW_ALIGNMENT > 1","description":"### Summary\n\nWhen [`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. \n\n### Details\n\nWith 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.\n\nTested vulnerable on 11.2.1, 12.3.0, 4c1ed27a5.\n\n### PoC\n\nWhether things leak may depend on allocator configuration. This does show a leak on my Mac.\n\n```python\nimport os\n\nos.environ[\"PILLOW_ALIGNMENT\"] = \"64\"\n\nfrom PIL import Image\n\n# Image A: 64 px wide, so its rows fill the whole aligned stride\na = Image.new(\"L\", (64, 40), 0x41).transpose(Image.Transpose.FLIP_LEFT_RIGHT)\ndel a\n\n# Image B: 61 px wide, so each row has 3 bytes of padding; its pixels are all 0\nb = Image.new(\"L\", (61, 40), 0).transpose(Image.Transpose.FLIP_LEFT_RIGHT)\n\ntry:\n    exported = Image.fromarrow(b, b.mode, b.size).tobytes()\nexcept ValueError as e:\n    print(\"Not vulnerable:\", e)\nelse:\n    if leaked := len(exported) - exported.count(0):\n        raise RuntimeError(f\"{leaked} of {len(exported)} exported bytes are not B's pixels\")\n```\n\n### Impact\n\nInformation 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.","summary":"Pillow's Arrow export returns uninitialized heap memory mixed into image pixel data when the PILLOW_ALIGNMENT environment variable is set above 1. That memory can contain pixels from images the process freed earlier, so a caller can read another image's data.","severity":"medium","cvss":6.3,"epss":0.00384,"exploited":false,"exploited_at":null,"products":[{"name":"Pillow","fixed":["13.0.0"],"affected":">= 11.2.1, < 13.0.0","ecosystem":"pypi"}],"ecosystems":["pypi"],"tags":["cwe-226","cwe-908","multi-tenant-image-services","package","pillow","python"],"not_affected_if":["no-arrow-export","pillow-13-or-later","pillow_alignment-unset"],"how_to_check":"Run: python -c \"import os; print(os.environ.get('PILLOW_ALIGNMENT'))\" in the service environment; a value above 1 plus Arrow export (Image.fromarrow / to Arrow) means exposure.\nCheck installed version: pip show pillow.","fix":"Upgrade Pillow to 13.0.0 or later (pip install -U 'pillow>=13.0.0').\nAs an interim step, unset PILLOW_ALIGNMENT or keep it at 1.","status":"open","published_at":"2026-10-21T22:16:49+00:00","first_seen_at":"2026-10-23T21:56:55+00:00","triaged_at":"2026-10-23T21:57:11+00:00","updated_at":"2026-10-23T21:57:29+00:00","category":"package","confidence":0.8,"triage":{"at":"2026-10-23T21:57:11Z","model":"claude-haiku-5-5","output":{"fix":"Upgrade Pillow to 13.0.0 or later (pip install -U 'pillow>=13.0.0').\nAs an interim step, unset PILLOW_ALIGNMENT or keep it at 1.","reach":"unknown","impact":"medium","summary":"Pillow's Arrow export returns uninitialized heap memory mixed into image pixel data when the PILLOW_ALIGNMENT environment variable is set above 1. That memory can contain pixels from images the process freed earlier, so a caller can read another image's data.","category":"package","who_cares":["python","pillow","multi-tenant-image-services"],"confidence":0.8,"needs_auth":"unknown","worst_case":"Attacker reads leftover heap pixels from other users' images","analyst_note":"","how_to_check":"Run: python -c \"import os; print(os.environ.get('PILLOW_ALIGNMENT'))\" in the service environment; a value above 1 plus Arrow export (Image.fromarrow / to Arrow) means exposure.\nCheck installed version: pip show pillow.\nunknown","needs_analyst":false,"not_affected_if":["PILLOW_ALIGNMENT-unset","no-arrow-export","pillow-13-or-later"],"user_interaction":"no","needs_special_setup":"yes","severity_if_unknown":"medium"},"cost_usd":0.000581,"input_tokens":3478,"output_tokens":467,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'-114501':14A,22A '-2026':13A,21A '-226':25B '-908':27B '/en/stable/reference/block_allocator.html#memory-pools)':85C '0':149C,251C,257C,283C '0x41':227C '1':11A,58B,89C,121C '11.2.1':178C '12.3.0':179C '3':243C '40':226C,256C '4c1ed27a5':180C '5j9c':19A '61':236C,255C '64':204C,211C,225C '654x':17A 'align':10A,52B,82C,119C,130C,139C,203C,220C,306C,324C 'alloc':124C,188C 'anoth':75B,343C 'applic':302C 'arrow':2A,38B,94C,311C 'b':235C,252C,265C,295C 'b.mode':266C 'b.size':267C 'block':143C,148C 'byte':163C,169C,244C,292C 'caller':72B 'configur':189C 'contain':62B,340C 'content':351C 'cve':12A,20A 'cwe':24B,26B 'cwwv':18A 'data':48B,78B,104C,159C,338C 'default':123C 'del':232C 'depend':186C 'detail':116C 'disclosur':300C 'e':272C,276C 'earlier':69B,115C 'els':277C 'environ':53B 'except':269C 'export':3A,39B,90C,146C,158C,263C,281C,290C,291C,308C,337C 'exported.count':282C 'f':286C 'fill':217C 'first':135C,173C 'freed':68B,114C 'ghsa':16A 'ghsa-654x-cwwv-5j9c':15A 'handl':330C 'heap':6A,42B,97C,350C 'im':147C 'imag':31B,46B,65B,76B,92C,111C,208C,209C,234C,309C,314C,333C,346C 'image.fromarrow':264C 'image.new':223C,253C 'image.transpose.flip':229C,259C 'impact':298C 'import':199C,207C 'includ':108C,160C,166C 'inform':299C 'isn':318C 'l':224C,254C 'leak':4A,184C,194C,279C,287C 'left':230C,260C 'len':280C,289C 'length':317C 'like':312C 'lines':131C 'mac':197C 'may':185C 'memori':7A,43B,60B,98C,106C 'mix':44B,99C 'multi':29B 'multi-tenant-image-servic':28B 'multipl':321C 'offset':140C 'one':334C 'os':200C 'os.environ':201C 'pack':155C 'packag':33B 'pad':125C,162C,246C 'pil':206C 'pillow':1A,9A,23A,34B,36B,51B,81C,202C,305C 'pillow.readthedocs.io':84C 'pillow.readthedocs.io/en/stable/reference/block_allocator.html#memory-pools)':83C 'pixel':47B,63B,103C,109C,156C,248C,297C,341C 'poc':181C 'print':273C 'process':67B,113C 'ptr':150C 'px':212C,237C 'python':35B,198C 'rais':284C 'read':74B 'return':40B,95C 'right':231C,261C 'row':127C,136C,174C,216C,241C,316C 'runtimeerror':285C 'servic':32B,329C 'set':56B,87C,304C 'sever':331C 'show':192C 'stale':5A,349C 'start':133C 'stride':221C 'summari':79C 'tenant':30B 'test':175C 'thing':183C 'tight':154C 'tobyt':268C 'transpos':228C,258C 'tri':262C 'uniniti':41B,96C 'user':332C,335C,344C 'valueerror':270C 'variabl':54B 'vulner':176C,275C 'whether':182C 'whole':219C 'whose':315C 'wide':213C,238C 'xsize':152C 'ysize':153C","nicknames":[],"mitigations":[],"who_affected":null,"tier":"C","verified":{},"analyst_revisit_at":null,"first_public_at":"2026-10-21T22:16:49+00:00","kev":null,"cvss_vector":"CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","cvss_by":"security-advisories@github.com","poc_count":0,"sources":[{"source":"ghsa","external_id":"GHSA-654x-cwwv-5j9c","url":"https://github.com/advisories/GHSA-654x-cwwv-5j9c","severity":"medium","published_at":"2026-10-23T21:53:21+00:00","modified_at":"2026-10-23T21:53:25+00:00","first_seen_at":"2026-10-23T21:56:55+00:00","fetched_at":"2026-10-23T21:56:55+00:00","note":null},{"source":"nvd","external_id":"CVE-2026-114501","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-114501","severity":null,"published_at":"2026-10-21T22:16:49+00:00","modified_at":"2026-10-22T16:46:48+00:00","first_seen_at":"2026-10-23T21:57:29+00:00","fetched_at":"2026-10-23T22:29:02+00:00","note":null}],"documents":[],"notice":"Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai"}