python / python/cpython

lzma: unbounded dictionary-size allocation is a memory DoS (zipfile, tarfile, lzma.decompress)

Open
#155,649 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

extension-modules type-security
Dominant language
Python
Stars
77.2k
Forks
35.9k
PR merge metrics
PR metrics pending

Description

Bug: LZMA decompression accepts an attacker-controlled dictionary size with no bound, and liblzma allocates the full dictionary up front when a decompressor is created. A few bytes of input can therefore force a multi-gigabyte allocation (memory denial of service).

Attack surfaces (both reported by OSS-Fuzz, both public):

  • zipfile with an LZMA-compressed member: the 5-byte LZMA properties header in the member data declares the dictionary. A 1088-byte zip whose member declares a ~2 GiB dictionary OOMs the process. https://issues.oss-fuzz.com/issues/495472861
  • tarfile's compression-detection loop: a 13-byte input whose first byte is a valid LZMA-alone properties byte (0x66) and whose remaining bytes encode a ~4 GiB dictionary is tried as LZMA; liblzma allocates 4 GiB before failing. https://issues.oss-fuzz.com/issues/482161128

Also reachable directly: lzma.decompress() / LZMADecompressor(format=FORMAT_AUTO) on untrusted bytes, and LZMADecompressor(FORMAT_RAW, filters=[{"dict_size": ...}]).

Root cause: two gaps:

  1. parse_filter_spec_lzma() accepts any dict_size (up to UINT32_MAX) for raw LZMA1/LZMA2 filter chains; liblzma allocates that dictionary at decompressor creation.
  2. LZMADecompressor defaults memlimit to UINT64_MAX, so the FORMAT_ALONE/FORMAT_AUTO paths (where the header is parsed inside liblzma) are also unbounded.

Proposed fix (PR to follow):

  • Reject dict_size > LZMA_DICT_SIZE_MAX (1.5 GiB, liblzma's own maximum) in parse_filter_spec_lzma() with LZMAError.
  • Default the decompressor memlimit to LZMA_DICT_SIZE_MAX instead of UINT64_MAX (callers may still pass an explicit memlimit).

No legitimate streams are affected: liblzma presets cap at 64 MiB dictionaries, and 1.5 GiB is liblzma's own maximum supported dictionary size.

Reported by OSS-Fuzz (ClusterFuzz). Reproducers attached to the issues above.

Linked PRs
  • gh-155650

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with parse_filter_spec_lzma() and LZMADecompressor, then review the zipfile and tarfile paths described in the issue. Use the linked OSS-Fuzz reproducers to verify that oversized dictionaries no longer cause unbounded allocation, while normal LZMA streams and explicit memlimit behavior remain intact.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.