Live › vulnerability › CVE-2026-106118
Go to dashboardImageSharp allocates tile buffers sized by TileWidth but decodes tiled T4/T6 fax TIFFs using the full image width, so each row writes past the buffer. A crafted TIFF passed to Image.Load causes a deterministic process crash and an out-of-bounds heap write that may be exploitable for code execution.
Summary written from the sources below. Check the originals before acting.
First seen by InfraStack 2026-10-26 14:16 UTC, 0h before NVD. All times on this page are UTC.
Applications that call ImageSharp to decode untrusted TIFF files are exposed, because a single crafted tiled T4 or T6 file is enough to trigger the write. Exposure needs a tiled TIFF with fax compression reaching the decoder; applications that only process images they create, or that never load TIFF, can skip it.
| Product | Ecosystem | Affected | Fixed in |
|---|---|---|---|
| ImageSharp | nuget | >= 3.0.0, < 3.2.0 | 3.2.0 |
| ImageSharp | nuget | >= 4.0.0, < 4.1.1 | 4.1.1 |
dotnet list package in the project and look for SixLabors.ImageSharp below 3.2.0 or at 4.0.0 to 4.1.0.Image.Load and whether those files can be tiled with Compression=3 or 4.SixLabors.ImageSharp to 3.2.0 on the 3.x line.SixLabors.ImageSharp to 4.1.1 on the 4.x line.Each row is the first time that source carried this signal. The analyst’s rows are its own findings.
When decoding a tiled TIFF with fax compression (T4/T6/MH), DecodeTilesChunky allocates each tile buffer from TileWidth (ceil(TileWidth*bpp/8)*TileLength bytes) but constructs the fax decompressor with frame.Width: TiffDecompressorsFactory ignores the isTiled/tileWidth/tileHeight parameters entirely. The T4/T6/MH decompressors treat the full image width as the scanline length and advance (and really write, via read-modify-write bit ops) frame.Width bits per row, with no bounds check against the tile buffer. The very first tile therefore writes linearly out of bounds — about ImageWidth/8 bytes per row × TileLength rows into a TileWidth-sized buffer. With ImageWidth=4,000,000, TileWidth=16, TileLength=16 this writes ~2 MB past a 32-byte buffer and kills the process deterministically; a T6 all-white variant advances the bit offset by >512 MB silently, showing an alarm-free heap-corruption window for the same defect. A crafted file fully controls the OOB length per tile and works with perfectly legal per-row run codes (no overlong runs needed).
Verified at commit 5cd4d0d26a82a9549f297a237aea9cf665bddff8 (main; latest release v4.1.0, the supported major).
Root cause: a size mismatch between tile buffer allocation and decompressor width, because the factory drops the tile parameters.
bytesPerTileRow = RoundUpToMultipleOfEight(tileWidth*bitsPerPixel); tile buffer = bytesPerTileRow*tileLength bytes (32 bytes in the PoC)CreateDecompressor<TPixel>(frame.Width, ..., isTiled: true, tileWidth, tileLength) passes the full frame widthwidth (= frame.Width); isTiled/tileWidth/tileHeight ignoredT6TiffCompression.cs#L76-L108 — per-row advance of this.width bits via BitWriterUtils.WriteBits with no buffer-length check (BitWriterUtils.cs#L51); note TiffDecoderCore.cs:829-831 later reads the buffer in strides, confirming the protocol expects tile-width rowsAttack surface: Image.Load(stream) on an attacker-supplied tiled TIFF (TiffDecoderCore.DecodeImageWithTiles → DecodeTilesChunky). Default configuration; only requirement is a standard tiled TIFF header (TileWidth=16, TileLength=16) + Compression=3 (T4; T6 also constructible).
Suggested remediation:
isTiled, construct the T4/T6/MH decompressor with tileWidth (not frame width), or clip row writes to the caller-provided buffer length.BitWriterUtils (pass remaining bits), and validate every fax row advance against buffer capacity on both tiled and strip paths.WriteBit).Full PoC posted as the first comment below: Program.cs (driver), poc-tiled-t4.tif (crafted file, ~9.8 KB, base64 inline), README.
Build a small console project referencing src/ImageSharp/ImageSharp.csproj and run it against the crafted file (or call Image.Load on it from any host).
Observed with ImageWidth=4,000,000, TileWidth=16, TileLength=16, T4 with 400 makeup codes + EOL per row:
tile payload 9642 bytes; rows write ~2,048,000 bytes into a 32-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 ...T4TiffCompression.WritePixelRun(...)
at ...T4TiffCompression.Decompress(...)
Aborted (core dumped); exit=134
Controls: the same file with Compression=None decodes normally (container is fine); a T6 all-white-rows variant advances >512 MB of bit offset without a real write (silent corruption window) before tripping on a directory-level TileOffsets count check.
Reported by Kimi Security Team ([email protected]).
This page as .md · .json · in your agent: get_signal("CVE-2026-106118")
GitHub Advisory Database, CC-BY 4.0 · NVD data is provided by NIST and is public domain. Posts quoted belong to their authors.
bytesPerTileRow