Skip to content

LERC and JPEG2000 codecs lack decompression-bomb cap #1625

@brendancol

Description

@brendancol

Summary

lerc_decompress_with_mask (xrspatial/geotiff/_compression.py:1191) and jpeg2000_decompress (line 1114) call the underlying lerc.decode(data) / glymur.Jp2k(tmp)[:] with no pre-decode bound on the output size. The deflate / zstd / lz4 / packbits codecs all received a decompression-bomb cap in #1533, but LERC and JPEG2000 were missed.

Impact

A crafted GeoTIFF tile compressed with LERC or JPEG2000 can declare arbitrarily large pixel dimensions inside the codestream. The reader's post-decode size validation in _decode_strip_or_tile (line 793) catches the bomb only after the underlying library has materialised the full decoded buffer in memory, so the host is OOM-killed before the check fires.

LERC compresses constant-value blocks at >700,000:1: a 94-byte blob can decode to 64 MiB. A ~1 KB on-disk LERC tile can request multiple GB of host memory before the size check rejects it. JPEG2000 has similar amplification potential through tile-size declarations in the codestream.

Verification

import lerc, numpy as np
arr = np.zeros((4096, 4096), dtype=np.float32)
encoded = lerc.encode(arr, 1, False, None, 0.0, 1)
blob = bytes(encoded[2])
# 94 bytes -> 64 MB. info[4]=4096, info[5]=4096, info[6]=1 bands

The existing test_decompression_caps.py covers deflate / zstd / lz4 / packbits but not lerc / jpeg2000 / jpeg.

Fix

Pre-validate the codestream's declared output size against the caller-supplied expected_size * 1.05 + 1 cap before invoking the underlying library:

  • LERC: lerc.getLercBlobInfo(data) returns (errCode, version, dataType, nDim, nCols, nRows, nBands, ...) without decoding. Compute nCols * nRows * nBands * dtype_size and raise ValueError if it exceeds the margin cap.
  • JPEG2000: read glymur.Jp2k(tmp).shape before calling [:].

JPEG (Pillow) already has its own Image.MAX_IMAGE_PIXELS guard and emits Image.DecompressionBombError; it is protected at the library level and does not need a wrapper-level cap.

Severity

MEDIUM — exploitable only on readers that have the optional lerc / glymur packages installed, but no special privileges or crafted-bytestream knowledge is required beyond producing a tiny LERC blob with large declared dimensions.

Found by /sweep-security on the geotiff module (2026-05-11).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions