HexBrain

MariaDB · Report #3872239

Connector/J: malicious server crashes client JVM via unbounded result-set field-count allocation in ClientMessage.readPacket

Validstatus
mediumseverity
31upvotes
30 Sept 2026disclosed

How it was found

MariaDB Connector/J parses result-set responses by reading the column count as a length-encoded integer straight from the wire and immediately uses it to size a Java array (new ColumnDecoder[fieldCount]) with no upper bound. A malicious or MITM MariaDB server can reply to any query - or to the driver's own connection-setup query - with a ~10-byte packet declaring a field count of up to 2^31-1, causing the client JVM to attempt a multi-gigabyte allocation and die with java.lang.OutOfMemoryError. The crash is JVM-wide, taking down all pooled connections and application threads.

Root cause

src/main/java/org/mariadb/jdbc/message/ClientMessage.java:

default:
    int fieldCount = buf.readIntLengthEncodedNotNull();   // line 282: server-controlled
    ColumnDecoder[] ci;
    if (context.canSkipMeta() && this.canSkipMeta()) {
      ...
    } else {
      ci = new ColumnDecoder[fieldCount];                 // line 302: unbounded allocation
      for (int i = 0; i < fieldCount; i++) { ... }
    }

readIntLengthEncodedNotNull() (ReadableByteBuf.java:148) returns the wire value verbatim. For the 0xfe form it does return (int) readLong(), giving the server full control over the 32-bit integer:

  • fieldCount = 0x10000000 (268M) -> OutOfMemoryError: Java heap space
  • fieldCount = 0x7fffffff -> OutOfMemoryError: Requested array size exceeds VM limit
  • fieldCount = 0xffffffff -> NegativeArraySizeException

None are caught inside readPacket. OutOfMemoryError is JVM-wide - it destabilizes the entire client process.

The driver default is sslMode=DISABLE (plaintext, Configuration.java:309), so an on-path attacker can rewrite server responses without controlling the actual database.

Steps To Reproduce

Environment: OpenJDK 21, driver built from HEAD c9377bc (mariadb-java-client-3.5.9.jar).

Step 1 - Start the rogue server (rogue_server.py attached):

python3 rogue_server.py positive 0 &

The server completes a plaintext handshake, OKs the driver's setup query, then answers SELECT 1 with a result-set header declaring fieldCount = 0x10000000.

Step 2 - POSITIVE (attack) - run a standard JDBC client (OomClient.java attached):

java -Xmx256m -cp .:mariadb-java-client-3.5.9.jar OomClient "jdbc:mariadb://127.0.0.1:<port>/test?user=app&password=secret"

Output:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at org.mariadb.jdbc.message.ClientMessage.readPacket(ClientMessage.java:302)
        at org.mariadb.jdbc.client.impl.StandardClient.readPacket(StandardClient.java:1438)
        at org.mariadb.jdbc.client.impl.StandardClient.readResults(StandardClient.java:1377)
        at org.mariadb.jdbc.Statement.executeQuery(Statement.java:137)
        at OomClient.main(OomClient.java:22)
client exit code = 1

Connect-time variant (server mode connect - injects on the driver's own setup query):

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at org.mariadb.jdbc.message.ClientMessage.readPacket(ClientMessage.java:302)
        at org.mariadb.jdbc.client.impl.StandardClient.postConnectionQueries(StandardClient.java:816)
        at org.mariadb.jdbc.Driver.connect(Driver.java:75)

JVM dies inside DriverManager.getConnection() - no application query, no valid credentials needed.

Step 3 - NEGATIVE CONTROL (same driver, same URL, same SELECT 1, benign 1-column result):

connected; running SELECT 1
RESULT=1
CLEAN_EXIT
client exit code = 0

The only difference is the field-count value in the server's result-set header.

Supporting Material/References

  • Vulnerable line: ClientMessage.java:302 (new ColumnDecoder[fieldCount])
  • Same-family siblings: Reader.java:133 (unbounded accumulator), OkPacket.java:160 (new byte[readIntLengthEncodedNotNull()])
  • Accepted sibling: H1 #3835450 (connector-nodejs malicious-server DoS, Medium)
  • Attachments: rogue_server.py, OomClient.java, run_poc.sh, poc_evidence.txt

Impact

A malicious or MITM MariaDB server crashes the connecting client's JVM with OutOfMemoryError using a single small packet. The crash is JVM-wide - it brings down the entire client application, every pooled connection and worker thread, not just one query.

The crash fires during DriverManager.getConnection() (connect-time variant), before any application query and without valid credentials. Any service that opens a JDBC connection to an attacker-influenced endpoint - SSRF-style connection strings, MITM on a plaintext link, a compromised database host, or a hostile replica in a failover topology - is knocked over at connect time.

Preconditions: the client must open a connection whose bytes the attacker controls. The driver default is sslMode=DISABLE (plaintext), so any network-level MITM suffices. No authentication and no application-level query are required.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original