# ImageSharp: CCITT fax decompression (T4/Modified Huffman): unbounded WriteBits overflows strip buffer — heap OOB write in SixLabors.ImageSharp

Unbounded WriteBits in ImageSharp's CCITT T4/Modified Huffman TIFF decompressors lets a crafted strip TIFF write ~19MB past an 8-byte buffer, crashing or corrupting the heap.

- Payout: Research
- Severity: high
- Program: ImageSharp
- Found by: KimiSecurityTeam, nazeeh111, JimBobSquarePants
- Disclosed: 2026-10-07
- CVE: CVE-2026-106117
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-jj3q-cwqj-842r
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-jj3q-cwqj-842r
- Tags: area:oss domain:oss impact:dos impact:integrity kind:research platform:ghsa sev:high tech:dotnet technique:fuzzing technique:source-review vuln:dos vuln:memory-corruption

**Target:** TIFF decoder (CCITT Group 3 1D / Modified Huffman strip decompression)
**Root cause:** BitWriterUtils.WriteBits/WriteBit/WriteZeroBit advance and write via Unsafe.Add with no comparison against buffer length; T4 only increments rowsWritten on EOL so unlimited makeup codes accumulate into one RunLength, and Modified Huffman writes before its pixelsWritten > Width check.
**Steps:**
1. Craft a strip TIFF: II, 42, ImageWidth=64, ImageLength=1, BitsPerSample=1, Photometric=WhiteIsZero, RowsPerStrip=1, Compression=3 (T4) or 2 (MH).
2. Set strip data to `EOL(12bit)` + 60000× `white makeup 2560 (000000011111)` + `white terminating code (000111)`, declaring a run of ~153,600,001 px.
3. Call `Image.Load(stream)` on the file (default config, no auth).
4. Observe AccessViolationException in `BitWriterUtils.WriteBits` via `T4TiffCompression.WritePixelRun` or `ModifiedHuffmanTiffCompression.Decompress`, process aborts (exit=134).
**How found:** Code review of the bit-writing sink found no bounds check against buffer length; tracing callers revealed T4's EOL-only row accounting lets makeup codes accumulate into one unbounded RunLength, and MH performs the write before validating width.
**Exploitation:** Attacker supplies a ~90KB strip TIFF to any service decoding untrusted images; the decompressor writes ~19.2MB linearly past an 8-byte strip buffer with attacker-controlled offset and length, causing an uncatchable fatal crash and a heap-corruption primitive on the managed heap.
**Insight:** When auditing image codecs, check the bit-writer sink itself for length bounds rather than trusting callers; also look for write-before-validate ordering and row counters that only advance on specific markers (EOL), which let run-length accumulators grow unbounded.

## Proof of concept (copied exactly from the original report)

**Crafted TIFF strip payload: EOL plus 60000 makeup codes**

```
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.
```

**PoC crash trace from WriteBits OOB write**

```
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<Byte>, IntPtr, IntPtr, Byte)
      at ...ModifiedHuffmanTiffCompression.Decompress(...)
      at SixLabors.ImageSharp.Formats.Tiff.TiffDecoderCore.DecodeStripsChunky[Rgba32](...)
   Aborted (core dumped); exit=134
```

