Skip to content

Security: unbounded allocation via TIFF tile dimensions (DoS) #1215

@brendancol

Description

@brendancol

Summary

The TIFF reader checks image dimensions but ignores tile dimensions. An adversarial TIFF can claim a 1x1 image (passes the existing guard) with a 2^30 x 2^30 tile (unchecked), and the decompressor will try to allocate terabytes.

Reproducer

Build a TIFF with:

  • ImageWidth=1, ImageLength=1 (passes the default ~1B pixel guard)
  • TileWidth=2^30, TileLength=2^30 (unchecked)

_decode_strip_or_tile in xrspatial/geotiff/_reader.py computes pixel_count = tw * th * samples ≈ 2^60 and passes it to decompress(). For LZW, lzw_decompress then does np.empty(expected_size, dtype=np.uint8) at terabyte scale. OOM.

Affected paths

  • _read_tiles (_reader.py:436) checks image dims at line 494 but not tw/th.
  • _read_cog_http (_reader.py:578) has the same gap.
  • read_geotiff_gpu (__init__.py:1005) checks image dims at line 1109, then gpu_decode_tiles does cupy.zeros(n_tiles * tile_width * tile_height * bytes_per_pixel) with no cap.

The strip path happens to be safe because strip_rows = min(rps, height - strip_row) pins it to the (checked) image height.

Threat model

TIFF from an untrusted source (HTTP, user upload, third-party mosaic) triggers unbounded allocation. No code execution, just DoS -- but a one-file DoS.

Proposed fix

After reading tile dims from the IFD, call _check_dimensions(tile_width, tile_height, samples, max_pixels) in _read_tiles, _read_cog_http, and read_geotiff_gpu. Legitimate COGs use tile_width <= 512, so capping per-tile pixels at max_pixels rejects the attack without breaking anything real.

Tests

  • A TIFF with small image dims + huge tile dims raises ValueError.
  • Normal tile sizes (256, 512) still pass.

Found during a security audit of the geotiff subpackage.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghigh-priorityinput-validationInput validation and error messagesoomOut-of-memory risk with large datasets

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions