---
id: CVE-2026-96637
aliases:
  - GHSA-g842-9rc4-69pw
  - BIT-pillow-2026-96637
  - PYSEC-2026-4338
title: >-
  Pillow: Decompression bomb check bypass in SpiderImagePlugin.seek() leads to
  unbounded allocation DoS
summary: >-
  Pillow: Decompression bomb check bypass in SpiderImagePlugin.seek() leads to
  unbounded allocation DoS
severity: high
cvss: 6.5
cvssVector: 'CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H'
vendor: pillow
product: pillow
ecosystem: pip
affected:
  - pillow < 13.0.0
patched:
  - pillow 13.0.0
published: '2026-10-22'
updated: '2026-10-29'
sourceUpdated: '2026-10-29T10:55:56.102454725Z'
source: OSV
sourceUrl: 'https://osv.dev/vulnerability/GHSA-g842-9rc4-69pw'
references:
  - url: >-
      https://github.com/python-pillow/Pillow/security/advisories/GHSA-g842-9rc4-69pw
  - url: 'https://nvd.nist.gov/vuln/detail/CVE-2026-96637'
  - url: 'https://github.com/python-pillow/Pillow/pull/10076'
  - url: >-
      https://github.com/python-pillow/Pillow/commit/7cb0e02389d8aac2a60896a490f572db0b07b841
  - url: 'https://github.com/python-pillow/Pillow'
  - url: 'https://github.com/python-pillow/Pillow/releases/tag/13.0.0'
  - url: 'https://github.com/advisories/GHSA-g842-9rc4-69pw'
tags:
  - osv
  - pip
  - cve.org
  - ghsa
cvssSource: osv
epss: 0.00373
epssPercentile: 0.31199
ssvc:
  exploitation: none
  automatable: 'yes'
  technicalImpact: partial
  timestamp: '2026-10-23T17:32:50.503938Z'
cwe:
  - CWE-400
  - CWE-409
scores:
  osv: 6.5
  cna: 7.1
ingestedAt: '2026-10-21T22:18:33.801Z'
---

## Overview

## Summary
SpiderImagePlugin's seek() bypasses the decompression bomb check, allowing a tiny (<1KB) crafted SPIDER stack file to trigger a multi-gigabyte allocation on im.load().

## Affected versions
All versions up to and including current HEAD (v13.0.0.dev0, commit e7a7ea84)

## Root cause
Image.open() runs Image._decompression_bomb_check(im.size) exactly once, in _open_core (src/PIL/Image.py:3668), right after the initial _open(). 

SPIDER stack files are multi-frame: SpiderImageFile.seek(frame) (SpiderImagePlugin.py:179-190) computes an attacker-influenced stkoffset and calls self._open() AGAIN directly (line 190) — NOT through Image.open(). _open() re-parses a fresh 27-float header at that offset and reassigns:

    self._size = int(h[12]), int(h[2])      # SpiderImagePlugin.py:131

straight from unvalidated header floats (isSpiderHeader only checks internal labrec*lenbyt==labbyt consistency, never bounds nsam/nrow). No bomb check runs on this new size.

On the subsequent load(), ImageFile.load_prepare() (ImageFile.py:436-437) executes `self.im = Image.core.new(self.mode, self.size)` with the unchecked, attacker-chosen size. Mode is always "F" (4 bytes/pixel), so e.g. 40000x40000 = 6.4 GB.

## Why this is a real bug
Sibling multi-frame plugins DO re-check on their alternate paths:
- GifImagePlugin.py:286 - Image._decompression_bomb_check(self._size) (in seek)
- TiffImagePlugin.py:1309 - Image._decompression_bomb_check(self._tile_size)
- IcnsImagePlugin.py:121/138, IcoImagePlugin.py:236/240 (sub-image selection)

SpiderImagePlugin has NO bomb check anywhere. This is the same class of bug just fixed for GdImageFile (GHSA-phj9-mv4w-65pm) and the FontFile classes (GHSA-5x94/8v84/45hq): an allocation reached on a non-Image.open() path sized by an attacker header field, independent of the one-time pixel bomb check.

## Reproduction
Python 3.13, Pillow HEAD e7a7ea84

Attached: pillow_poc_spider_bomb.py

Sets Image.MAX_IMAGE_PIXELS=5000, then:
- CONTROL: Image.open(standalone 100x100 SPIDER) -> DecompressionBombWarning fires correctly.
- BYPASS: Image.open(stack, frame0=1x1) passes; im.seek(1) sets size (100,100) with NO DecompressionBombWarning/Error -> the check is bypassed.

Real-world impact: a large frame-1 nsam/nrow (e.g. 40000x40000) causes im.load() to allocate ~6.4 GB (mode F) with the bomb check fully bypassed, from a file under 1 KB.

## Suggested fix
Call Image._decompression_bomb_check(self.size) at the end of SpiderImageFile._open() (or in seek() after _open()), mirroring GifImagePlugin / TiffImagePlugin. Optionally validate nsam/nrow are positive and sane in _open().

Credit: Yazan Balawneh - CyStack Security Team 
[pillow_poc_spider_bomb.py](https://github.com/user-attachments/files/30244916/pillow_poc_spider_bomb.py)

## Affected packages

- `pillow < 13.0.0`

## Remediation

Upgrade to a patched release:

- `pillow 13.0.0`
