On this page (8 sections)
Pillow, the widely used Python imaging library, has a critical memory-safety bug in the code that saves TIFF images to an in-memory target such as io.BytesIO. According to the GitHub advisory, every release from 2.0.0 up to but not including 13.0.0 is affected, and 13.0.0 contains the fix.
If your site or API accepts image uploads, opens them with Pillow and re-encodes them as TIFF without writing to a real file, this is worth checking today. Thumbnailers, media pipelines, document converters and CMS back ends are the typical places this pattern shows up.
At a glance
What happened
Pillow's TIFF writer hands libtiff a small in-memory buffer whenever the save target has no usable fileno(). While writing a TIFF directory, libtiff seeks past the current end of the data and writes tag values there, behaving as it would on a real file. The in-memory buffer sized its growth from the previous buffer size instead of the current write position, so a write after the seek could land beyond the allocation. The advisory describes the function involved as _tiffWriteProc in src/libImaging/TiffDecode.c.
The CVE record lists a publication date of 2026-10-19, while the GitHub advisory shows October 17, 2026. The 13.0.0 release notes show the release on 16 Oct. The sources do not explain the date difference, so treat the exact disclosure date as approximate. Only one independent publisher covers this story so far, so most details here come from the project's own advisory, commit and release notes.
Technical details in plain terms
Two separate problems come from the same code path:
- Heap buffer overflow: the bytes written past the end come from a tag value in the uploaded file. The advisory says the overrun can reach up to the size of the TIFF directory, which is 12 bytes per entry. It gives 126 bytes as the minimal case and 2384 bytes observed with a 331-entry directory.
- Stale heap disclosure: bytes that libtiff skips for alignment are never initialized. For compressed TIFF output larger than 64 KiB, the saved file can contain leftover heap bytes, one per padding hole. The advisory states this leak needs no crafted tag.
On impact, the sources are measured. The advisory says the reproducer crashes the process and that the overflow could potentially be developed further, but that code execution is not demonstrated. The CVE description says it can crash the process and may allow code execution. Plan for at least a reliable denial of service and an information leak, and do not assume code execution is ruled out.
What makes it reachable
The advisory says the ordinary re-encode sequence, opening an upload and saving it to BytesIO as TIFF with no options, reaches the vulnerable path with default settings, because compression is inherited from the source image. The overflow half also needs an attacker-sized out-of-line tag value to reach libtiff. That can happen when an opened TIFF is saved directly (ImageDescription, DocumentName or XMP tags) or through an embedded ICC profile, which the advisory says survives copy() in im.info. Operations such as convert(), resize() and thumbnail() drop the tag entries, but the compression hint and ICC profile can still carry through.
Saves to a file path, or to any target with a real file descriptor, are unaffected.
Who is affected
You are realistically exposed if all of these are true:
- You run Pillow older than 13.0.0 in any Python environment, including containers and virtual environments.
- Untrusted users can supply images that your code opens.
- Your code saves output as TIFF to BytesIO, an HTTP response object or a storage backend stream rather than to a file path.
If you only save to other formats, or only write TIFF to real files, the described path is not used. Even so, upgrading is the simplest way to be sure.
How to check your exposure
First, find the installed version. This read-only command prints the Pillow version in the active Python environment; anything below 13.0.0 is affected.
python -m pip show PillowNext, search your code for TIFF saves to in-memory targets. This grep lists lines that mention BytesIO or TIFF so you can review which ones pass an in-memory stream to save(). Run it from your project root; matches are leads to review, not proof of exposure.
grep -rnE "BytesIO|TIFF|tiff" --include="*.py" .Remember to check every place Pillow lives: application virtualenvs, Docker images, CI build caches, serverless bundles and any vendored copies pinned in requirements files or lock files.
What to do now
0 of 6 done
This command upgrades Pillow to the fixed release. Run it in the target virtualenv, then restart the app.
python -m pip install --upgrade "Pillow>=13.0.0"After upgrading, run the pip show command again to confirm the version is 13.0.0 or higher, then restart your web workers and background queues.
If you cannot upgrade immediately
The research does not list an official workaround, so upgrading is the supported fix. As a temporary risk reduction only, consider blocking TIFF uploads at your application or edge, or saving TIFF output to a real file path instead of an in-memory stream. Both follow from the advisory's description of which paths are affected, but neither replaces the patch. A website firewall can help filter unwanted upload types; see what a WAF does.
Detection and monitoring
A crash is the most visible symptom. The advisory's reproducer aborts with a glibc message, malloc(): corrupted top size, so search application and system logs for that text and for unexpected worker exits around image uploads. The stale-memory leak is harder to see, because it silently places leftover heap bytes inside generated TIFF files. If you stored TIFF files created through this path from untrusted input, treat them as possibly containing fragments of process memory before sharing them further.
Keep an eye on dependency alerts for Python packages in your build pipeline, and re-scan after deployments. Webforta's security scanner can check the externally visible side of sites you verify, though it cannot see which library versions run inside your server.
Fix details
The upstream patch changes the buffer growth calculation to use the current write location, zeroes newly allocated space so skipped bytes are 0 as they would be in a file, and rejects invalid writes with an error. It also adds tests comparing BytesIO output with file output. The sources do not say the fix was backported to any release before 13.0.0, so upgrading to 13.0.0 is the confirmed route.
Sources
This article is based on the public sources below. Details can change as vendors and researchers publish more; check the original advisories before acting on version numbers.
