Describe the bug
When reading a primitive array, Kryo allocates the array from the declared length before validating it against the bytes actually remaining in the input. A few-byte input that declares a huge length causes an immediate OutOfMemoryError (new int[length] with no bound). Input.readInts and its siblings (readLongs/readFloats/readDoubles/...) and the array/collection serializers share this pattern.
Reporting this as a robustness/hardening issue. I am aware Kryo is not intended for deserializing untrusted data; filing in case bounding the initial allocation is considered worthwhile.
To Reproduce
Minimal runnable example (5-byte input):
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.*;
public class KryoPoc {
public static void main(String[] a) {
Kryo kryo = new Kryo();
kryo.register(int[].class); // typical application registration
Output o = new Output(16);
o.writeVarInt(2000000001, true); // length+1 -> declared int[] length 2,000,000,000
o.flush();
byte[] evil = o.toBytes(); // 5 bytes; no element payload follows
kryo.readObject(new Input(evil), int[].class); // OutOfMemoryError here
}
}
Result:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.esotericsoftware.kryo.io.Input.readInts(Input.java:968)
The input declares a 2,000,000,000-element array but carries no element data; Kryo allocates new int[2000000000] before checking that the input could possibly contain that many elements.
Environment:
- OS: macOS 26.5.1 (25F80)
- JDK Version: 21
- Kryo Version: 5.6.2 (latest)
Suggested fix
Bound the initial allocation to the bytes remaining in the input (a primitive element is at least 1 byte, so the declared length cannot exceed the remaining byte count), or read and grow in chunks rather than pre-allocating the full declared length. Found via boundary-value testing as part of academic research.
Describe the bug
When reading a primitive array, Kryo allocates the array from the declared length before validating it against the bytes actually remaining in the input. A few-byte input that declares a huge length causes an immediate
OutOfMemoryError(new int[length]with no bound).Input.readIntsand its siblings (readLongs/readFloats/readDoubles/...) and the array/collection serializers share this pattern.Reporting this as a robustness/hardening issue. I am aware Kryo is not intended for deserializing untrusted data; filing in case bounding the initial allocation is considered worthwhile.
To Reproduce
Minimal runnable example (5-byte input):
Result:
The input declares a 2,000,000,000-element array but carries no element data; Kryo allocates
new int[2000000000]before checking that the input could possibly contain that many elements.Environment:
Suggested fix
Bound the initial allocation to the bytes remaining in the input (a primitive element is at least 1 byte, so the declared length cannot exceed the remaining byte count), or read and grow in chunks rather than pre-allocating the full declared length. Found via boundary-value testing as part of academic research.