From 03f0e0330cc34ac15cab110290cb7d80db23790d Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 19:33:09 +0000 Subject: [PATCH] Fix integer overflow and DoS in ImageData.Read - Add check for positive dimensions - Ensure total calculated pixels size does not exceed 1 GB footprint - Prevent out-of-bounds/memory exhaustion DoS when parsing crafted files Co-authored-by: johnstrand <11484777+johnstrand@users.noreply.github.com> --- src/GameUtils/Types/ImageData.cs | 13 ++++++- tests/GameUtils.Tests/Types/ImageDataTests.cs | 34 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/GameUtils/Types/ImageData.cs b/src/GameUtils/Types/ImageData.cs index 1c609fc..8ebfd4a 100644 --- a/src/GameUtils/Types/ImageData.cs +++ b/src/GameUtils/Types/ImageData.cs @@ -158,7 +158,18 @@ public static ImageData Read(Stream source) var width = reader.ReadInt32(); var height = reader.ReadInt32(); - var data = new Vector4[width * height]; + if (width <= 0 || height <= 0) + { + throw new InvalidDataException("Width and height must be positive"); + } + + long totalPixels = (long)width * height; + if (totalPixels > 67_108_864) // 1 GB max memory allocation (16 bytes per Vector4) + { + throw new InvalidDataException("Image size exceeds maximum allowed limit of 1GB"); + } + + var data = new Vector4[(int)totalPixels]; for (var i = 0; i < data.Length; i++) { data[i] = new Vector4( diff --git a/tests/GameUtils.Tests/Types/ImageDataTests.cs b/tests/GameUtils.Tests/Types/ImageDataTests.cs index 93451b8..b7bffd1 100644 --- a/tests/GameUtils.Tests/Types/ImageDataTests.cs +++ b/tests/GameUtils.Tests/Types/ImageDataTests.cs @@ -8,6 +8,40 @@ namespace GameUtils.Tests.Types [TestClass] public class ImageDataTests { + [TestMethod] + public void Read_WithNegativeDimensions_ThrowsInvalidDataException() + { + using var ms = new MemoryStream(); + using (var compressor = new System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionLevel.Optimal, true)) + using (var writer = new BinaryWriter(compressor)) + { + writer.Write("IMGD"u8); + writer.Write(-1); + writer.Write(10); + } + + ms.Position = 0; + + Assert.ThrowsExactly(() => ImageData.Read(ms)); + } + + [TestMethod] + public void Read_WithExcessiveDimensions_ThrowsInvalidDataException() + { + using var ms = new MemoryStream(); + using (var compressor = new System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionLevel.Optimal, true)) + using (var writer = new BinaryWriter(compressor)) + { + writer.Write("IMGD"u8); + writer.Write(20000); + writer.Write(20000); // 400M pixels > 67.1M limit + } + + ms.Position = 0; + + Assert.ThrowsExactly(() => ImageData.Read(ms)); + } + [TestMethod] public void Write_WithTraversalPath_ThrowsUnauthorizedAccessException() {