Commit Graph
2 Commits
Author SHA1 Message Date
Marc-André Bombeck 933be858c5 fix(images): size a GIF by its largest frame, not only its logical screen
The header check before a thumbnail decode read only the GIF logical screen.
A decoder sizes its buffer from the frame's image descriptor, so a file with a
small screen and a huge frame passed the pixel cap and allocated the full
frame. Walk every block, read each image descriptor, size the image by the
largest of screen and frames, and refuse a file that ends inside a header or
descriptor, carries an unknown block, or has no frame.
2026-10-25 16:53:31 +01:00
Marc-André Bombeck ba22932101 fix(documents): read a JPEG's size past fill bytes and refuse an unreadable one
The thumbnail's header walk took the byte after any 0xFF as a marker. A
single 0xFF fill byte after the start-of-image marker, which the JPEG
standard allows and every decoder skips, threw it off; it read no size, and
an unread size let the image through to a decode that allocates the full
bitmap. A small JPEG declaring 20000 x 20000 pixels allocated 1.6 GB in the
web process before the post-decode check could see it.

The avatar upload already had a walker that skips fill bytes. Both now use
one reader (lib/image-dimensions) that follows the marker rules: fill bytes,
the length-less markers, and no size when a scan or the end of the image
comes before a frame header. The thumbnail treats an unreadable size as a
refusal (size-unreadable) for every format it decodes, and the backfill
counts that refusal as final.
2026-10-25 13:52:04 +01:00