Prerequisites
ImageSharp version
3.1.12
Other ImageSharp packages and versions
N/A — only SixLabors.ImageSharp
Environment (Operating system, version and so on)
Linux (WSL2, Ubuntu 22.04) and Windows 11
.NET Framework version
.NET 10.0
Description
A crafted BMP file with bitsPerPixel = 0 in the DIB header causes an unhandled DivideByZeroException in BmpDecoderCore.ReadRgbPalette. This exception is not part of the ImageSharp exception hierarchy (ImageFormatException / InvalidImageContentException / UnknownImageFormatException), so applications following the documented error handling pattern cannot catch it.
For comparison, other malformed inputs (truncated PNG, random garbage, etc.) correctly throw InvalidImageContentException or UnknownImageFormatException.
The root cause is in BmpDecoderCore.ReadRgbPalette:
int ppb = 8 / bitsPerPixel; // DivideByZeroException when bitsPerPixel == 0
The Decode() method routes to ReadRgbPalette when BmpCompression.RGB and BitsPerPixel <= 8 — a value of 0 matches this condition.
A suggested fix would be to validate bitsPerPixel before the switch:
if (bitsPerPixel is not (1 or 2 or 4 or 8 or 16 or 24 or 32))
{
BmpThrowHelper.ThrowInvalidImageContentException($"Invalid bits per pixel: {bitsPerPixel}");
}
Found by coverage-guided fuzzing with SharpFuzz + AFL++.
Steps to Reproduce
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
// Construct minimal BMP with bitsPerPixel = 0
var bmp = new byte[54];
bmp[0] = (byte)'B'; bmp[1] = (byte)'M';
BitConverter.GetBytes(54).CopyTo(bmp, 2);
BitConverter.GetBytes(54).CopyTo(bmp, 10);
BitConverter.GetBytes(40).CopyTo(bmp, 14);
BitConverter.GetBytes(1).CopyTo(bmp, 18);
BitConverter.GetBytes(1).CopyTo(bmp, 22);
BitConverter.GetBytes((short)1).CopyTo(bmp, 26);
BitConverter.GetBytes((short)0).CopyTo(bmp, 28); // bitsPerPixel = 0
using var stream = new MemoryStream(bmp);
using var image = Image.Load<Rgba32>(stream); // throws DivideByZeroException
Stack trace:
System.DivideByZeroException: Attempted to divide by zero.
at SixLabors.ImageSharp.Formats.Bmp.BmpDecoderCore.ReadRgbPalette[TPixel](
BufferedReadStream stream, Buffer2D`1 pixels, Byte[] colors,
Int32 width, Int32 height, Int32 bitsPerPixel,
Int32 bytesPerColorMapEntry, Boolean inverted)
at SixLabors.ImageSharp.Formats.Bmp.BmpDecoderCore.Decode[TPixel](
BufferedReadStream stream, CancellationToken cancellationToken)
at SixLabors.ImageSharp.Formats.ImageDecoderCore.Decode[TPixel](...)
at SixLabors.ImageSharp.Image.Load[TPixel](Stream stream)
Images
N/A — the reproduction is fully inline above (54-byte constructed BMP).
Prerequisites
DEBUGandRELEASEmodeImageSharp version
3.1.12
Other ImageSharp packages and versions
N/A — only SixLabors.ImageSharp
Environment (Operating system, version and so on)
Linux (WSL2, Ubuntu 22.04) and Windows 11
.NET Framework version
.NET 10.0
Description
A crafted BMP file with
bitsPerPixel = 0in the DIB header causes an unhandledDivideByZeroExceptioninBmpDecoderCore.ReadRgbPalette. This exception is not part of the ImageSharp exception hierarchy (ImageFormatException/InvalidImageContentException/UnknownImageFormatException), so applications following the documented error handling pattern cannot catch it.For comparison, other malformed inputs (truncated PNG, random garbage, etc.) correctly throw
InvalidImageContentExceptionorUnknownImageFormatException.The root cause is in
BmpDecoderCore.ReadRgbPalette:The
Decode()method routes toReadRgbPalettewhenBmpCompression.RGBandBitsPerPixel <= 8— a value of 0 matches this condition.A suggested fix would be to validate
bitsPerPixelbefore the switch:Found by coverage-guided fuzzing with SharpFuzz + AFL++.
Steps to Reproduce
Stack trace:
Images
N/A — the reproduction is fully inline above (54-byte constructed BMP).