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).
Summary
lerc_decompress_with_mask(xrspatial/geotiff/_compression.py:1191) andjpeg2000_decompress(line 1114) call the underlyinglerc.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
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 + 1cap before invoking the underlying library:lerc.getLercBlobInfo(data)returns(errCode, version, dataType, nDim, nCols, nRows, nBands, ...)without decoding. ComputenCols * nRows * nBands * dtype_sizeand raiseValueErrorif it exceeds the margin cap.glymur.Jp2k(tmp).shapebefore calling[:].JPEG (Pillow) already has its own
Image.MAX_IMAGE_PIXELSguard and emitsImage.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/glymurpackages installed, but no special privileges or crafted-bytestream knowledge is required beyond producing a tiny LERC blob with large declared dimensions.Found by
/sweep-securityon the geotiff module (2026-05-11).