Skip to content

A large-dimension image raises an uncaught DecompressionBombError instead of returning a response #3378

Description

@adamtheturtle

What happens

A PNG with large dimensions but a small file size makes the mock raise an uncaught PIL.Image.DecompressionBombError instead of returning a response.

A 20000x20000 single-colour greyscale PNG compresses to 388 KB, so it passes the 2 MB file size checks, but decodes to 400 million pixels. Pillow refuses to open it: Image.open runs _decompression_bomb_check and raises once the pixel count exceeds twice Image.MAX_IMAGE_PIXELS, which is 178,956,970 pixels by default.

Both APIs are affected:

POST /targets  -> UNCAUGHT DecompressionBombError Image size (400000000 pixels) exceeds limit of 178956970 pixels
POST /v1/query -> UNCAUGHT DecompressionBombError Image size (400000000 pixels) exceeds limit of 178956970 pixels

DecompressionBombError inherits from Exception, not from OSError, so the except OSError in _query_validators/image_validators.py::validate_image_is_image does not catch it, and neither does the except SyntaxError in _services_validators/image_validators.py::validate_image_integrity.

Through the requests and httpx backends the exception propagates out of the caller's requests.post. Through Flask and Docker it is a 500.

A consequence worth noting separately

validate_image_dimensions in src/mock_vws/_query_validators/image_validators.py checks:

max_width = 30000
max_height = 30000

Those limits are unreachable. Pillow raises at roughly 13,376 x 13,376 for a square image, so no image which would fail this check can ever be opened to be checked. The branch is dead code, and the mock therefore has no working maximum dimension check at all.

Why it matters

Real Vuforia returns a documented result code here rather than failing to respond. Anyone whose test suite feeds the mock a generated or fuzzed image, or a legitimately large scan, gets an exception from their HTTP client rather than the error response their code is written to handle — which is the specific thing a mock exists to let them test.

Suggested resolution

Catch Image.DecompressionBombError alongside the exceptions already handled in the image validators for both APIs, and return whatever real Vuforia returns for an oversized image. That needs checking against a real database to decide between BadImage and ImageTooLarge, and against the Query API for its own equivalent, so this wants a verified fake test rather than a guess.

The dimension limits then need revisiting. Either raise Image.MAX_IMAGE_PIXELS inside the mock so that the documented 30000 x 30000 limit becomes reachable and is genuinely enforced, or lower the mock's limit to something Pillow can actually reach and record the difference in docs/source/differences-to-vws.rst. Leaving an unreachable constant in place is the one option worth ruling out.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions