GitHub Advisoryadvisory · NuGet
GHSA-jj3q-cwqj-842r ImageSharp: CCITT fax decompression (T4/Modified Huffman): unbounded WriteBits overflows strip buffer — heap OOB write in SixLabors.ImageSharp
HIGH
Official page ↗
- Aliases
- CVE-2026-106117
- Ecosystem
- NuGet
- Packages
- ImageSharp
- Severity
- High
- CVSS vector
- CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
- Weaknesses
- CWE-787
- Reviewed
- 2026-10-07
Affected packages
• NuGet ImageSharp: >= 3.0.0, < 3.2.0 → fixed in 3.2.0
• NuGet ImageSharp: >= 4.0.0, < 4.1.1 → fixed in 4.1.1
Description
Summary
When decoding a fax-compressed strip TIFF (Compression=3 / Group 3 1D, or Compression=2 / Modified Huffman), the CCITT decompressors write decoded runs through `BitWriterUtils.WriteBits/WriteBit/WriteZeroBit`, which advance and write bits via `Unsafe.Add` with read-modify-write semantics — without ever comparing the write position against the target buffer length. The strip buffer is sized `ImageWidth × RowsPerStrip` (8 bytes in the PoC), but two independent defects let an attacker write tens of millions of bits past it: (a) T4 only increments `rowsWritten` when an EOL code is read, and one `ReadNextRun` accumulates unlimited makeup codes (+2560 px per 12-bit code) into a single `RunLength` that `WritePixelRun` then writes in one shot; (b) Modified Huffman writes before validating (`pixelsWritten > Width` is checked at :90-93, after the write at :56-63), so the overflow completes even though an exception is thrown later. One crafted ~90 KB file writes ~19.2 MB linearly past an 8-byte buffer and deterministically kills the process; the write offset and length are fully attacker-controlled (classic heap-corruption primitive on the managed heap).
Verified at commit `5cd4d0d26a82a9549f297a237aea9cf665bddff8` (main; latest release v4.1.0, the supported major). A related tiled-path variant (tile-buffer width mismatch) was reported separately as GHSA-v76p-62qx-wwq2 — this report covers the distinct strip-path root cause.
Details
Root cause: the bit-writing sink has no bounds check, and neither decompressor constrains run lengths against the strip buffer.
• Unchecked write primitive: BitWriterUtils.cs#L51 (`WriteBit`), :58 (`WriteZeroBit` — also read-modify-write, so even all-white runs really write), :11 (`WriteBits`)
• T4 trigger: T4TiffCompression.cs#L75 and L109-L119 — `rowsWritten` only increments on EOL; consecutive makeup codes accumulate into one `RunLength`, then `WritePixelRun` writes it in full
• MH trigger: ModifiedHuffmanTiffCompression.cs#L56-L63 — write happens before the width check at L90-L93
• Buffer size: TiffDecoderCore.cs#L932-L967 — `CalculateStripBufferSize` = width × bpp/8 × rowsPerStrip
Attack surface: `Image.Load(stream)` on an attacker-supplied strip TIFF (`TiffDecoderCore.DecodeStripsChunky` → `TiffDecompressorsFactory.Create` → `Decompress`). Default configuration, no authentication, no user interaction — a plain strip TIFF (far more common than the tiled variant) with Compression=2 or 3 and a chain of CCITT makeup codes.
Relationship to GHSA-v76p-62qx-wwq2: that report is the tiled variant — a caller-side width mismatch (`TiffDecompressorsFactory` drops tile parameters) that overflows with perfectly legal run codes. This report is the strip variant — the callee-side missing bounds check plus T4's EOL-only row accounting and MH's write-before-validate. Fixing the caller mismatch does not address this vector; bounding `BitWriterUtils` addresses both (see remediation).
Suggested remediation:
1. Bound `BitWriterUtils.WriteBits/WriteBit/WriteZeroBit` against `buffer.Length*8` (return bool / throw `ImageFormatException`) — do not rely on caller discipline.
2. In the T4/MH decompress loops, validate `(bitsWritten + RunLength) Width` check before the actual write.
4. Regression fuzz cases: Compression=2/3, EOL-less oversized makeup chains, edge widths; strip and tiled paths share the same constraint.
PoC
Full PoC posted as the first comment below: `Program.cs` (driver), `poc-tiff-t4.tif` + `poc-tiff-mh.tif` (crafted files, ~90 KB each, base64 inline), README.
1. Build a console project referencing `src/ImageSharp/ImageSharp.csproj`, run it against either crafted file (or call `Image.Load` on it).
2. PoC layout: TIFF (II, 42), ImageWidth=64, ImageLength=1, BitsPerSample=1, Photometric=WhiteIsZero, RowsPerStrip=1; strip data = `EOL(12bit)` + 60000× `white makeup 2560 (000000011111)` + `white terminating code (000111)` — declared run ≈ 153,600,001 px ≈ 19.2 MB into an 8-byte buffer.
3. Observed (both variants):
```
strip payload 90003 bytes, claimed run ~153,600,001 px = 19,200,000 bytes into 8-byte buffer
Fatal error. System.AccessViolationException: Attempted to read or write protected memory.
at SixLabors.ImageSharp.Formats.Tiff.Compression.BitWriterUtils.WriteBits(Span`1, IntPtr, IntPtr, Byte)
at ...ModifiedHuffmanTiffCompression.Decompress(...)
at SixLabors.ImageSharp.Formats.Tiff.TiffDecoderCore.DecodeStripsChunkyRgba32
Aborted (core dumped); exit=134
```
The T4 variant crashes identically at `T4TiffCompression.WritePixelRun → BitWriterUtils.WriteBits`.
4. Control: an equivalent file without the makeup chain (legal EOL-delimited rows) decodes normally — the crash comes from the oversized runs, not the container.
Impact
• What it is: out-of-bounds write (CWE-787). For any service decoding untrusted TIFFs (image hosting/transcoding/thumbnails/CMS): reliable remote DoS (uncatchable fatal process crash), plus a heap OOB write with attacker-controlled offset and length — a realistic heap-corruption / potential code-execution surface. In scope of your SECURITY.md as a library vulnerability.
• Who is impacted: applications decoding untrusted TIFF with SixLabors.ImageSharp at the current major (verified on main past v4.1.0); plain strip TIFFs with Compression=2/3 are the trigger, which ordinary TIFF writers can produce.
---
---
Reported by Kimi Security Team ([email protected]).
Related
Alias · CVE (1)
- CVE-2026-106117 ImageSharp is a 2D graphics library. vulnerability
Weakness · CWE (1)
- CWE-787 Out-of-bounds Write weakness
References
- https://github.com/SixLabors/ImageSharp/security/advisories/GHSA-jj3q-cwqj-842r web
- https://nvd.nist.gov/vuln/detail/CVE-2026-106117 advisory
- https://github.com/SixLabors/ImageSharp/pull/3176 web
- https://github.com/SixLabors/ImageSharp/commit/e8892ecd8a95dee95c4480fda51cfe0b32f3b846 web
- https://github.com/SixLabors/ImageSharp package
- https://github.com/SixLabors/ImageSharp/releases/tag/v3.2.0 web
- https://github.com/SixLabors/ImageSharp/releases/tag/v4.1.1 web