{"id":"GHSA-cp9v-662q-vvx9","aliases":["BIT-pillow-2026-112405","CVE-2026-112405","PYSEC-2026-4333"],"title":"Pillow: NULL pointer dereference in Image.merge via an unvalidated band 0","titleSource":"OSV","descriptionSource":"OSV","declaredSeverity":"HIGH","description":"### Summary\n`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.\n\n### Details\nThe validation loop skips band 0:\n\n- `src/PIL/Image.py:3795` iterates `for band in bands[1:]` and checks mode and size only for those.\n\nFor 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:\n\n- `src/libImaging/Bands.c:302`, `:311`, `:321`\n\nThe IPTC loader builds the band list from an attacker-typed sub-image and passes it to merge with the sub-image at index 0:\n\n- `src/PIL/IptcImagePlugin.py:156-160`\n- `src/PIL/IptcImagePlugin.py:169` registers the opener with no accept function.\n\n### PoC\n```python\nfrom PIL import Image\n\n# Band 0 is a single-band \"I\" image: its image8 plane is NULL. merge() validates only\n# bands[1:], so the native ImagingMerge dereferences the NULL plane for band 0.\nband0 = Image.new(\"I\", (4, 4))\nImage.merge(\"RGB\", [band0, Image.new(\"L\", (4, 4)), Image.new(\"L\", (4, 4))])\n```\n\nRun it:\n```\n$ python 02_poc.py\nSegmentation fault (core dumped)\n```\n\nObserved on a source build of commit `3e2ab96`.\n\nUnder AddressSanitizer:\n```\n==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000\n    #0 ImagingMerge   src/libImaging/Bands.c:311\n    #1 _merge         src/_imaging.c:2492\nSUMMARY: AddressSanitizer: SEGV src/libImaging/Bands.c:311 in ImagingMerge\n```\nThe null address confirms the dereference of the missing `image8` plane for band 0.\n\n### Impact\nNULL 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.","severity":"high","score":8.7,"published":"2026-10-19T22:17:08.027Z","modified":"2026-10-28T11:10:36.014Z","withdrawn":false,"knownExploited":false,"affected":[{"ecosystem":"PyPI","name":"pillow","sources":[{"name":"OSV · GHSA-cp9v-662q-vvx9","url":"https://osv.dev/vulnerability/GHSA-cp9v-662q-vvx9"}],"ranges":[{"events":[{"introduced":"12.0.0"},{"fixed":"13.0.0"}],"type":"ECOSYSTEM"}],"versions":["12.0.0","12.1.0","12.1.1","12.2.0","12.3.0"],"fixed":["13.0.0"]},{"ecosystem":"PyPI","name":"pillow","sources":[{"name":"OSV · PYSEC-2026-4333","url":"https://osv.dev/vulnerability/PYSEC-2026-4333"}],"ranges":[{"events":[{"introduced":"12.0.0"},{"fixed":"13.0.0"}],"type":"ECOSYSTEM"}],"versions":["12.0.0","12.1.0","12.1.1","12.2.0","12.3.0"],"fixed":["13.0.0"]}],"sourceAffected":[],"references":["https://github.com/python-pillow/Pillow/security/advisories/GHSA-cp9v-662q-vvx9","https://nvd.nist.gov/vuln/detail/CVE-2026-112405","https://github.com/python-pillow/Pillow/commit/b6ee66e8b2c2c0932bdf65f963268d9f2927ef86","https://github.com/python-pillow/Pillow","https://github.com/python-pillow/Pillow/releases/tag/13.0.0"],"sources":[{"name":"OSV","id":"GHSA-cp9v-662q-vvx9","modified":"2026-10-28T11:10:36.014536437Z","url":"https://osv.dev/vulnerability/GHSA-cp9v-662q-vvx9"},{"name":"OSV","id":"PYSEC-2026-4333","modified":"2026-10-28T11:10:36.014536437Z","url":"https://osv.dev/vulnerability/PYSEC-2026-4333"}],"assessments":[{"source":"OSV","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","score":8.7},{"source":"OSV","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","score":7.5}],"products":[],"remediation":[],"kev":{"status":"not-listed","checkedAt":"2026-10-28T20:25:31.474Z"},"coverage":[{"source":"NVD","status":"available","checkedAt":"2026-10-28T12:00:36.682Z","attemptedAt":"2026-10-28T12:00:36.682Z"},{"source":"GHSA","status":"available","checkedAt":"2026-10-28T12:00:35.551Z","attemptedAt":"2026-10-28T12:00:35.551Z"},{"source":"EUVD","status":"available","checkedAt":"2026-10-28T12:00:34.346Z","attemptedAt":"2026-10-28T12:00:34.346Z"},{"source":"EPSS","status":"available","checkedAt":"2026-10-28T12:00:32.165Z","attemptedAt":"2026-10-28T12:00:32.165Z"}],"evidence":[{"source":"FIRST EPSS","id":"CVE-2026-112405","url":"https://www.first.org/epss/","probability":0.00417,"percentile":0.35872,"date":"2026-10-27","checkedAt":"2026-10-28T12:00:32.165Z"},{"source":"ENISA EUVD","id":"EUVD-2026-104646","url":"https://euvd.enisa.europa.eu/vulnerability/EUVD-2026-104646","modified":"Oct 20, 2026, 3:56:29 PM","score":8.7,"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","checkedAt":"2026-10-28T12:00:34.346Z"},{"source":"GitHub Advisory Database","id":"GHSA-cp9v-662q-vvx9","url":"https://github.com/advisories/GHSA-cp9v-662q-vvx9","modified":"2026-10-21T20:30:26Z","checkedAt":"2026-10-28T12:00:35.551Z"},{"source":"NVD","id":"CVE-2026-112405","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-112405","modified":"2026-10-27T14:59:59.923","score":8.7,"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/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","checkedAt":"2026-10-28T12:00:36.682Z"},{"source":"NVD","id":"CVE-2026-112405","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-112405","modified":"2026-10-27T14:59:59.923","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","checkedAt":"2026-10-28T12:00:36.682Z"}]}