Skip to content

Upgrading pillow 12 to 13

Breaking12.3.0 → 13.0.0Breaking4Security53Platform2Deprecated4New8Changed84Fixed113Other105

BreakingUpgrade verdict

4 breaking changes and 2 platform requirement changes and 47 security fixes.

  • APIs that were deprecated in earlier releases have now been removed.
  • Code that expected the XMP metadata value to be a tuple will now get a different type.
  • An internal, undocumented helper for saving GIFs as Netpbm files is gone.
  • The Makernote entry in the ExifTags IFD enum is no longer available.
Top 5 of 57 that need code or config changes

Python requirement changed in 13.0.0: >=3.10 → >=3.11.

Breaking4
Removes deprecations scheduled for Pillow 13.0.0.
XMP info is no longer returned as a tuple.
Image.info
Removes the undocumented GifImagePlugin._save_netpbm function.
GifImagePlugin._save_netpbm
Removes ExifTags.IFD.Makernote.
ExifTags.IFD.Makernote
Security47
Pillow: TIFF encoder ColorMap plane-size mismatch causes a heap out-of-bounds read
High · CVSS 7.1
Pillow: Heap buffer overflow in _tiffWriteProc when saving TIFF to BytesIO
_tiffWriteProcBytesIOCritical
Applies uclouvain/openjpeg#1621 to address OSV-2025-219.
Rejects JPEG streams whose scanlines are wider or have more components than expected.
Pillow: Heap over-read in WMF/EMF rendering via 16-bit dimension truncation (Windows builds)
High · CVSS 8.1
Fixes a use-after-free when a libtiff encode error occurs.
Pillow: EPS load(scale) lets Ghostscript render past the decompression bomb limit
Moderate
Adds a decompression bomb check to grabclipboard() on Windows.
grabclipboard()
Pillow: Decompression bomb check bypass in SpiderImagePlugin.seek() leads to unbounded allocation DoS
Medium · CVSS 6.5
Fixes an out-of-bounds read in C getlist() and _putdata() when __len__ overstates length.
getlist()_putdata()__len__
Pillow: Decompression-bomb protection bypass via multi-frame seek() in MPO and DCX (MpoImageFile.seek / DcxImageFile.seek)
Medium · CVSS 6.5
Adds a decompression bomb check when loading WmfStubImageFile at a different DPI.
WmfStubImageFile
Pillow tiled-TIFF decoder reads past tile buffer in copy4 (Unpack.c:1290)
Moderate · CVSS 6.5
Pillow: Out-of-bounds access in _imagingmorph on a zero-width image
High · CVSS 7.5
Pillow: GIF seek keeps rejected size after DecompressionBombError, allowing DoS
High
Pillow: Heap buffer overflow in ImagingJpegDecode
Critical · CVSS 9.8
Pillow: OOB read in TiffDecode.c tile and RGBA paths leaks heap memory into pixels
High
Pillow: Unbounded recursion parsing a PDF page tree or trailer chain (incomplete fix for CVE-2026-42310)
High
Pillow: TiffDecode returns uninitialized memory as pixels for short JPEG strips
High
Pillow: APNG background disposal allocates full canvas before decompression bomb check
High
Pillow: Quadratic GIF comment concatenation allows DoS in Image.open()
Moderate
Pillow: Infinite loop in MIC n_frames when the embedded TIFF
High
Pillow: PdfParser can recurse without limit in get_value() and linearize_page_tree()
Moderate
Pillow: Bundled libopenjp2 2.5.4 in all wheels since 11.1.0 carries OSV-2025-219 heap-buffer-overflow write reachable from Image.open().load()
High · CVSS 8.1
Pillow: NULL dereference in ImagingExpand via rank filters on zero-size images
High · CVSS 7.5
Pillow: P;2L and P;4L decoders may read 1 to 3 bytes past the passed buffer size
High · CVSS 8.2
Pillow: Heap use-after-free when encoding TIFF to an in-memory buffer
High · CVSS 7.5
Pillow: Double free in ImagingScaleAffine on calloc failure via Image.transform
High · CVSS 7.5
Pillow: NULL pointer dereference in Image.merge via an unvalidated band 0
High · CVSS 7.5
Pillow: Infinite loop in PdfParser.rewrite_pages on page tree Parent cycle
High
Pillow: Quadratic GIF comment copying during save
Moderate
Pillow: MSP RLE decoder expands a tiny file into unbounded memory
High
Pillow: Invalid free in FreeType glyph rendering when a stroker is active
High
Pillow: Quadratic-time DoS in PDF save_all (PdfParser.next_object_id)
High
Pillow: Image.quantize() with empty palette leaks uninitialized stack memory
Moderate
Pillow: Argument Injection in Ghostscript call, potentially leading into RCE
Critical
Pillow: ReDoS in XbmImagePlugin: 512-byte file stalls Image.open() for minutes
High · CVSS 7.5
Pillow: Memory disclosure and segfault in libtiff encoder via crafted TIFF tags
High
Pillow: Heap buffer overflow writing JPEG comment after ICC profile fills buffer
High
Pillow: Reachable undefined behavior in native integer operations, potentially leading to denial of service or logic integrity compromise
Medium · CVSS 6.5
Pillow: BMP RLE decoder memory-amplification DoS via unbounded delta escape / absolute mode
Moderate · CVSS 6.5
Pillow multi-frame loaders can reuse stale native image storage after mode transitions
Critical · CVSS 9.8
Pillow PDF append accepts malformed shared page-tree DAG causing resource exhaustion
High
Pillow: TarIO negative size field causes infinite CPU-spin loop
Medium · CVSS 6.5
Pillow: PNG eXIf chunk makes EXIF parsing run in quadratic time
Medium · CVSS 6.5
Pillow: Heap buffer overflow in FlashPix (FPX) JPEG decoding leads to code execution
Critical · CVSS 9.8
Pillow: Arrow export leaks stale heap memory when PILLOW_ALIGNMENT > 1
Medium · CVSS 5.3
Platform2
Drops support for Python 3.10.
Adds support for Python 3.15.
Deprecated4
Deprecates the IM image format.
Deprecates ImageQt align8to32() in favour of the raw encoder stride.
ImageQt.align8to32()
Deprecates JpegImageFile.load_djpeg.
JpegImageFile.load_djpeg
Removes the type hint for the deprecated im.putdata(im.getdata()) pattern.
Image.putdata()Image.getdata()

Generated by DepDelta from published Python source. Not mixed with prose notes.

  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • removed: field IFD.Makernote
  • changed: method FontFile.save(filename: str) -> None → method FontFile.save(filename: str | os.PathLike[str]) -> None
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • changed: static method GimpPaletteFile.frombytes(data: bytes) -> GimpPaletteFile → static method GimpPaletteFile.frombytes(data: bytes) -> Self
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • removed: method Image.get_child_images() -> list[ImageFile.ImageFile]
  • removed: variable ElementTree
  • removed: variable ElementTree: ModuleType | None
  • removed: variable logger
  • changed: function frombuffer(mode: str, size: tuple[int, int], data: bytes | SupportsArrayInterface, decoder_name: str=…, *args: Any) -> Image → function frombuffer(mode: str, size: tuple[int, int], data: bytes | bytearray | SupportsArrayInterface, decoder_name: str=…, *args: Any) -> Image
  • changed: method Image.convert(mode: str | None=…, matrix: tuple[float, ...] | None=…, dither: Dither | None=…, palette: Palette=…, colors: int=…) -> Image → method Image.convert(mode: str | None=…, matrix: list[float] | tuple[float, ...] | None=…, dither: Dither | None=…, palette: Palette=…, colors: int=…) -> Image
  • changed: method Image.getxmp() -> dict[str, Any] → method Image.getxmp(*, strip_namespaces: bool=…) -> dict[str, Any]
  • changed: method Image.putdata(data: Sequence[float] | Sequence[Sequence[int]] | core.ImagingCore | NumpyArray, scale: float=…, offset: float=…) -> None → method Image.putdata(data: Sequence[float] | Sequence[Sequence[int]] | NumpyArray, scale: float=…, offset: float=…) -> None
  • added: field Resampling.MKS2013
  • added: field Resampling.MKS2021
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • changed: field Axis.name: bytes | None → field Axis.name: NotRequired[bytes]
  • changed: function load(filename: str) -> ImageFont → function load(filename: str | os.PathLike[str]) -> ImageFont
  • changed: function load_path(filename: str | bytes) -> ImageFont → function load_path(filename: StrOrBytesPath) -> ImageFont
  • changed: function crop(image: Image.Image, border: int=…) -> Image.Image → function crop(image: Image.Image, border: int | tuple[int, ...]=…) -> Image.Image
  • added: variable TYPE_CHECKING
  • changed: method ImagePalette.getdata() -> tuple[str, Sequence[int] | bytes | bytearray] → method ImagePalette.getdata() -> tuple[str, bytes]
  • added: variable TYPE_CHECKING
  • removed: property Stat.sum -> list[float]
  • removed: property Stat.sum2 -> list[float]
  • added: property Stat.sum -> list[int]
  • added: property Stat.sum2 -> list[int]
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • changed: method PSDraw.text(xy: tuple[int, int], text: str) -> None → method PSDraw.text(xy: tuple[int, int], text: str, *, escape: bool=…) -> None
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • removed: property SpiderImageFile.is_animated -> bool
  • removed: property SpiderImageFile.n_frames -> int
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING
  • added: variable TYPE_CHECKING