Skip to content

Validate BMP bit depth and pixel data length before allocating the image - #3223

Merged
JimBobSquarePants merged 3 commits into
SixLabors:mainfrom
jafin:jf/bmp-header-validation
Oct 27, 2026
Merged

JimBobSquarePants merged 3 commits into
SixLabors:mainfrom
jafin:jf/bmp-header-validation

Conversation

@jafin

@jafin jafin commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Prerequisites

  • I have written a descriptive pull-request title
  • I have verified that there are no overlapping pull-requests open
  • I have verified that I am following the existing coding patterns and practice as demonstrated in the repository. These follow strict Stylecop rules 👮.
  • I have provided test coverage for my change (where applicable)

Description

Reject unsupported BI_RGB bit depths during header parsing. Both Image.Identify and Image.Load now throw InvalidImageContentException for depths other than 1, 2, 4, 8, 16, 24 and 32.

Before allocating pixel storage, check that uncompressed RGB and bit-fields data can contain the declared rows. A tiny file can otherwise request a large image, or leave most of a row unread without an error. Count available rows by division so maximum-width, maximum-height 32-bit headers cannot overflow the length check.

Both checks remain fatal under every SegmentIntegrityHandling mode. Invalid pixel layouts and dimensions that cannot fit the available data cannot be decoded safely. RLE data is excluded from the fixed-size check. Missing padding after the final stored row remains supported, including top-down bitmaps.

Testing

All new test inputs are stored files. The 13 fixtures total 1,228 bytes and cover invalid RGB depths, truncated RGB and bit-fields data, maximum dimensions, and final-row padding in both row orders. Their headers, masks, lengths and intended truncations were independently checked. Pillow also confirms the pixels in both valid fixtures. Tests use the existing TestFile cache and TestMemoryAllocator; no input images or BMP payloads are generated during tests.

Current main fails all 11 malformed-file cases. The original patch still reaches allocation for the maximum-dimension fixture. Allocation assertions now reject any Rgba32 allocation, including split buffers.

Release .NET 10 verification:

  • BMP, ICO, CUR and ANI tests: 392 passed.
  • General format and invalid-dimension tests: 50 passed.

No tolerances or reference images changed. The branch includes current main.

Fixes #3235.

An uncompressed bitmap with a bit depth other than 1, 2, 4, 8, 16, 24 or 32 was
accepted by Identify, and Load failed with an ImageFormatException or a
NotSupportedException depending on the depth. The header reader now rejects such
depths with an InvalidImageContentException, so identification and decoding agree.

An uncompressed or bit fields header could also declare far more pixel data than the
stream holds. The decoder allocated the full pixel buffer before the first row read
failed, and a single short row decoded without error. The declared pixel data is now
checked against the remaining stream before the image is allocated; only the padding
of the last row may be missing.
@JimBobSquarePants

Copy link
Copy Markdown
Member

Hi @jafin thank you for these contributions. Could you please raise relevant issues, so we have something to track for release notes.

@jafin

jafin commented Oct 18, 2026

Copy link
Copy Markdown
Contributor Author

@JimBobSquarePants no worries, Issues are there now

Count available complete rows after reserving the final row's pixel bytes.
This avoids long overflow for maximum 32-bit BMP dimensions and rejects
impossible dimensions before any pixel buffer request in every integrity mode.
Retain missing final padding and both stored row orders.

Replace the PR's runtime BMP builder and encoder-generated input with 13 fixed
files (1228 bytes total). Independently check their headers, lengths, masks,
and intended truncations; Pillow also verifies both valid pixel arrays.
Extend allocation assertions to detect any Rgba32 allocation, including split
buffers, rather than only one allocation the size of the complete image.

Current main fails 11 malformed-file cases; the original patch still fails
the maximum-dimension regression. Release .NET 10: 392 BMP/ICO/CUR/ANI tests
and 50 general format/dimension tests pass with the corrected patch.
@JimBobSquarePants
JimBobSquarePants merged commit 93a186c into SixLabors:main Oct 27, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BMP decoder accepts invalid uncompressed bit depths in Identify and allocates the full pixel buffer for truncated files

2 participants