Skip to content

gh-156002: Bound zipfile decompression for bzip2/LZMA/Zstandard - #156003

Open
encukou wants to merge 8 commits into
python:mainfrom
encukou:fix-zipfile-decompress-maxlength
Open

gh-156002: Bound zipfile decompression for bzip2/LZMA/Zstandard#156003
encukou wants to merge 8 commits into
python:mainfrom
encukou:fix-zipfile-decompress-maxlength

Conversation

@encukou

@encukou encukou commented Aug 18, 2026

Copy link
Copy Markdown
Member

tonghuaroot and others added 6 commits June 23, 2026 09:34
…dard

zipfile.ZipExtFile._read1() bounds the output of each decompress() call
for DEFLATE members by passing a max_length to zlib, but for bzip2, LZMA,
and Zstandard members it called decompress() with no bound. A whole
compressed chunk was therefore expanded into a single allocation before
the data[:self._left] clip ran, so a consumer that deliberately reads in
small chunks to limit memory (for example zf.open(name).read(8192)) was
silently unprotected for non-DEFLATE members. A small, spec-conformant
archive member declaring a large uncompressed size could drive multi-GB
peak memory.

_read1() now passes a per-call bound to the non-DEFLATE decompress()
(mirroring the DEFLATE branch) and drains the decompressor's internal
buffer across calls by checking needs_input before reading more
compressed input. zipfile's LZMADecompressor wrapper forwards max_length
and exposes needs_input so the bound also holds for LZMA members.
Replace the Linux-only subprocess RSS test with a cross-platform check
that _read1() output is bounded by MIN_READ_SIZE for bzip2/LZMA/Zstandard.
Comment thread Lib/zipfile/__init__.py


def _decompressor_needs_input(decompressor):
# bz2/zstd expose the stdlib decompressor's public needs_input; the LZMA

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The LZMA wrapper is private, it's not in __all__ or documented, why not just make it a "public" property and avoid this little dance?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's one definition of “private” :)

For the backports, I think it's best to be extra careful. Testing on 3.14.7 and having things break with 3.14.6 is not fun.

Let's make it public (& more maintainable) in 3.16 afterwards.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be in Security.

@tonghuaroot

Copy link
Copy Markdown
Contributor

Agreed — this bounds a decompression-bomb DoS, so Security is the right blurb category. Thanks for landing it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants