You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
zipfile.ZipExtFile._read1() bounds the output of each decompress() call for DEFLATE members (it passes a max_length to zlib), but for bzip2 / LZMA / Zstandard members it called self._decompressor.decompress(data) with no bound. A whole compressed chunk was therefore expanded into a single allocation before the data = data[:self._left] clip ran.
$ head -c 1000000 /dev/urandom | base64 > payload.txt
$ 7z a -tzip -mm=Deflate64 d64.zip payload.txt
$ pip install zipfile-deflate64
$ python -c "import zipfile, zipfile_deflate64; zipfile.ZipFile('d64.zip').read('payload.txt')"# 3.13.15: works. With this patch applied:
AttributeError: 'zipfile_deflate64.deflate64.Deflate64' object has no attribute '_needs_input'
It changes what ZipExtFile._read1() requires of a non-deflate decompressor: previously it was enough to register a third-party decompressor through _get_decompressor(), now you need a decompress(data, max_length) method and a needs_input/_needs_input attribute.
I realize that _get_decompressor() is private, but this seems to be the standard method to extend zipfile, and this seems like a lot of breakage for a low severity issue (CVSS 2.1).
It should be pretty easy to fix the vulnerability for the stdlib decompressors and leave the third-party decompressors alone.
def _decompressor_needs_input(decompressor):
# bz2/zstd expose the stdlib decompressor's public needs_input; the LZMA
# wrapper keeps it private (_needs_input) to avoid adding public API.
needs_input = getattr(decompressor, "needs_input", None)
- return decompressor._needs_input if needs_input is None else needs_input+ if needs_input is None:+ return getattr(decompressor, "_needs_input", None)+ return needs_input
else:
- if _decompressor_needs_input(self._decompressor):+ needs_input = _decompressor_needs_input(self._decompressor)+ if needs_input is None or needs_input:
data = self._read2(n)
else:
data = b''
...
else:
- data = self._decompressor.decompress(data, max(n, self.MIN_READ_SIZE))- self._eof = (self._decompressor.eof or- self._compress_left <= 0 and- _decompressor_needs_input(self._decompressor))+ if needs_input is None:+ data = self._decompressor.decompress(data)+ self._eof = self._decompressor.eof or self._compress_left <= 0+ else:+ data = self._decompressor.decompress(data, max(n, self.MIN_READ_SIZE))+ self._eof = (self._decompressor.eof or+ self._compress_left <= 0 and+ _decompressor_needs_input(self._decompressor))
Activity
gh-156002: Bound zipfile decompression for bzip2/LZMA/Zstandard (GH-1…
pythongh-156002: Bound zipfile decompression for bzip2/LZMA/Zstandard (…
[3.15] gh-156002: Bound zipfile decompression for bzip2/LZMA/Zstandard (
rasmusfaber commentedon Sep 3, 2026
Please note that this change and its backports breaks zipfile-deflate64, zipfile-zstd etc.
It changes what
ZipExtFile._read1()requires of a non-deflate decompressor: previously it was enough to register a third-party decompressor through_get_decompressor(), now you need adecompress(data, max_length)method and aneeds_input/_needs_inputattribute.I realize that
_get_decompressor()is private, but this seems to be the standard method to extend zipfile, and this seems like a lot of breakage for a low severity issue (CVSS 2.1).It should be pretty easy to fix the vulnerability for the stdlib decompressors and leave the third-party decompressors alone.
def _decompressor_needs_input(decompressor): # bz2/zstd expose the stdlib decompressor's public needs_input; the LZMA # wrapper keeps it private (_needs_input) to avoid adding public API. needs_input = getattr(decompressor, "needs_input", None) - return decompressor._needs_input if needs_input is None else needs_input + if needs_input is None: + return getattr(decompressor, "_needs_input", None) + return needs_inputHappy to open a PR if you want.
[3.14] gh-156002: Bound zipfile decompression for bzip2/LZMA/Zstandard (
7 remaining items
pythongh-156002: Keep reading through monkey-patched zipfile decompre…
pythongh-156002: Keep reading through monkey-patched zipfile decompre…
pythongh-156002: Keep reading through monkey-patched zipfile decompre…
pythongh-156002: Keep reading through monkey-patched zipfile decompre…
Update python314 to version 3.14.7 / rev 40 via SR 1379535
Update python311 to version 3.11.16 / rev 74 via SR 1379773
[3.13] gh-156002: Bound zipfile decompression for bzip2/LZMA (GH-156003…
[3.12] gh-156002: Bound zipfile decompression for bzip2/LZMA/Zstandard (
[3.10] gh-156002: Bound zipfile decompression for bzip2/LZMA/Zstandard (
[3.11] gh-156002: Bound zipfile decompression for bzip2/LZMA/Zstandard (
Update python313 to version 3.13.15 / rev 46 via SR 1381538
Update python310 to version 3.10.21 / rev 83 via SR 1381747
Update python312 to version 3.12.14 / rev 54 via SR 1381748