Skip to content

IndexOutOfRangeException in PngPhysical.Parse with truncated pHYs chunk #3078

@pawlos

Description

@pawlos

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

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 10

.NET Framework version

.NET 10.0 (SDK 10.0.103 / Runtime 10.0.3)

Description

A crafted 24-byte PNG file with a truncated pHYs chunk causes an unhandled IndexOutOfRangeException in PngPhysical.Parse. The pHYs chunk normally contains 9 bytes (4 + 4 + 1), but the parser does not validate the data length before reading.

This exception is not part of the ImageSharp exception hierarchy (ImageFormatException / InvalidImageContentException), so applications following the documented error handling pattern cannot catch it.

The root cause is that PngPhysical.Parse() accesses fixed offsets in the data span without first checking that the span has the required 9 bytes.

Found by coverage-guided fuzzing with SharpFuzz + AFL++.

Steps to Reproduce

using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;

// 24 bytes — PNG signature + truncated pHYs chunk
byte[] payload = Convert.FromHexString(
    "89504e470d0a1a0a3030303070485973" +
    "3030303030303030");

using var stream = new MemoryStream(payload);
using var image = Image.Load<Rgba32>(stream);  // throws IndexOutOfRangeException

Stack trace

System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at SixLabors.ImageSharp.Formats.Png.Chunks.PngPhysical.Parse(ReadOnlySpan`1 data)
   at SixLabors.ImageSharp.Formats.Png.PngDecoderCore.ReadPhysicalChunk(ImageMetadata metadata, ReadOnlySpan`1 data)
   at SixLabors.ImageSharp.Formats.Png.PngDecoderCore.Decode[TPixel](BufferedReadStream stream, CancellationToken cancellationToken)
   at SixLabors.ImageSharp.Formats.ImageDecoderCore.Decode[TPixel](Configuration configuration, Stream stream, CancellationToken cancellationToken)
   at SixLabors.ImageSharp.Image.Load[TPixel](Stream stream)

Root Cause & Suggested Fix

PngPhysical.Parse() should validate the span length before reading:

public static PngPhysical Parse(ReadOnlySpan<byte> data)
{
    if (data.Length < 9)
    {
        ThrowInvalidImageContentException("pHYs chunk is too short");
    }
    // ... existing code
}

Images

N/A — the reproduction is fully inline above (24-byte constructed PNG).

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions