Skip to content

Unbounded new int[length] from declared array length in Input.readInts → OutOfMemoryError on malformed input #1282

Description

@joszamama

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions