CVE-2026-15310 Overview
CVE-2026-15310 is a resource exhaustion vulnerability in Python's zipfile module. When decompressing crafted ZIP archives that use bzip2, LZMA, or Zstandard compression, Python trusts an attacker-controlled size value to pre-allocate memory. A small archive member can therefore trigger an unbounded allocation, even when the caller reads the stream in small chunks. The flaw is tracked under CWE-400: Uncontrolled Resource Consumption and affects standard-library ZIP handling used across build systems, CI pipelines, package installers, and web applications.
Critical Impact
A single malicious ZIP file can force a Python process to allocate large amounts of memory, causing denial of service in services that accept user-supplied archives.
Affected Products
- CPython zipfile module (bzip2, LZMA, and Zstandard decompression paths)
- Applications and services that process untrusted ZIP archives through the standard library
- CI/CD, packaging, and file-processing pipelines relying on Python for archive extraction
Discovery Timeline
- 2026-08-25 - CVE-2026-15310 published to NVD
- 2026-08-26 - Last updated in NVD database
Technical Details for CVE-2026-15310
Vulnerability Analysis
The zipfile module reads compressed members using per-compression decompressor wrappers. For the deflate codec, reads were already bounded by an internal chunk limit. The bzip2, LZMA, and Zstandard paths did not enforce an equivalent bound. Instead, the code passed through the uncompressed size declared inside the ZIP central directory and local file headers. That value is attacker-controlled and unauthenticated.
Because the declared size drove memory pre-allocation, an attacker could craft a small archive whose header claims a very large uncompressed size. The decompressor would then attempt to reserve memory proportional to that claim before any real data was produced. Reading the archive in small chunks did not mitigate the issue, since the allocation happened upfront.
The practical outcome is memory exhaustion in the process performing the extraction. In server-side or long-running contexts, this can degrade or crash the service. Exploitation requires the victim to open or extract a crafted archive, which aligns with the user-interaction requirement in the CVSS vector.
Root Cause
The root cause is missing bounds enforcement on per-read decompression for the bzip2, LZMA, and Zstandard branches inside Lib/zipfile/__init__.py. The wrappers exposed a decompress(data) method without a max_length parameter, so callers could not cap output, and the module itself did not cap it internally. The fix introduces decompress(self, data, max_length=-1) and a matching _needs_input property so a bounded call can be drained across reads.
Attack Vector
An attacker delivers a crafted ZIP file to any application that extracts archives using Python's zipfile module. Delivery paths include file upload endpoints, email attachments, package artifacts, and content ingestion pipelines. No authentication is required, but a user or automated process must open the archive.
# Patched decompressor wrapper in Lib/zipfile/__init__.py
# Source: https://github.com/python/cpython/commit/f897dbf2f36a5935700b7c2d94d4681d2136b7d4
except AttributeError:
return b''
@property
def _needs_input(self):
# While the LZMA properties header is still being buffered, more input
# is required; afterwards defer to the wrapped decompressor so a bounded
# decompress() call can be drained across reads.
if self._decomp is None:
return True
return self._decomp.needs_input
def decompress(self, data, max_length=-1):
if self._decomp is None:
self._unconsumed += data
if len(self._unconsumed) <= 4:
The patch adds a max_length parameter and a _needs_input property so the caller can bound each read and drain a single decompress() call across multiple iterations.
Detection Methods for CVE-2026-15310
Indicators of Compromise
- Python worker processes with sudden, large resident memory growth immediately after receiving or opening a ZIP file.
- Out-of-memory kills (oom-killer on Linux) affecting services that call zipfile.ZipFile.extractall() or open() on archive members.
- ZIP archives whose declared uncompressed size for bzip2, LZMA, or Zstandard members is disproportionately large versus the compressed size.
Detection Strategies
- Inspect uploaded or ingested ZIP files and flag members using compression methods 12 (bzip2), 14 (LZMA), or 93 (Zstandard) with declared uncompressed sizes above a defined threshold.
- Enable memory and CPU accounting on archive-processing workers and alert on abrupt allocation spikes correlated with archive intake.
- Log the Python runtime version on all servers that process archives, and inventory hosts running unpatched CPython builds.
Monitoring Recommendations
- Track per-process RSS growth on services that call the zipfile module and alert when growth exceeds expected member sizes.
- Forward archive-processing telemetry, including source IP and file hash, into a central log store for correlation across ingestion attempts.
- Watch for repeated failed extractions from the same source, which can indicate probing for the memory-exhaustion condition.
How to Mitigate CVE-2026-15310
Immediate Actions Required
- Upgrade CPython to a version that includes the fix from python/cpython PR #156003 tracked in issue #156002.
- Audit applications that call zipfile.ZipFile on untrusted input and restrict accepted compression methods where feasible.
- Enforce per-process memory limits on any worker that decompresses user-supplied archives.
Patch Information
The fix is committed in CPython as f897dbf2f36a5935700b7c2d94d4681d2136b7d4 and announced on the Python security-announce list. The change bounds per-read decompression for bzip2, LZMA, and Zstandard members in Lib/zipfile/__init__.py, matching the existing behavior for deflate.
Workarounds
- Reject ZIP members that use bzip2, LZMA, or Zstandard compression until the runtime is patched.
- Validate the declared uncompressed size in each ZIP central directory entry and refuse archives whose totals exceed a policy limit.
- Run archive extraction in an isolated process with a hard memory cap using resource.setrlimit(resource.RLIMIT_AS, ...) or container-level limits.
# Configuration example: enforce a memory ceiling on the extractor process
systemd-run --scope -p MemoryMax=512M -p MemorySwapMax=0 \
/usr/bin/python3 /opt/app/extract_zip.py /tmp/incoming.zip
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

