HPACK Bomb

A decompression-bomb flaw in the HTTP/2 HPACK header codec that lets an unauthenticated attacker exhaust server memory and take the process down.

CVSS: 7.5 (High) | CWE-409 Data Amplification

Understanding the Threat

Discovered: August 3, 2016 (Public disclosure)
Researcher: Imperva Defense Center, as part of its HTTP/2 protocol analysis

HPACK Bomb is a denial-of-service flaw in hpack, the Python implementation of HTTP/2's HPACK header-compression format (RFC 7541). It is a classic decompression bomb: a tiny compressed payload that expands into an enormous amount of data once the server unpacks it.

Because HTTP/2 negotiates compression before any request body or authentication, the attack is unauthenticated. A mere 16 kB header block can decompress to 64 MB — a 4,096:1 ratio — and a handful of blocks is enough to force the target to allocate gigabytes and crash.

Attack Diagram
Figure 1: HPACK Bomb Attack Path

🚨 Why This Matters

  • 4,096:1 ratio — 16 kB in, 64 MB out, per header block
  • Unauthenticated — Triggered during HTTP/2 header exchange, before any auth
  • Cheap to send — A few crafted blocks exhaust gigabytes of RAM
  • Protocol-level — Any service decoding attacker HPACK is exposed
  • No exploit needed — The "payload" is just well-formed header references

Am I Vulnerable?

If your service decodes HTTP/2 headers using the Python hpack library below version 2.3.0 — or the hyper client below 0.6.0, which bundled a vulnerable copy — an attacker can crash it. Check your installed version:

Terminal
python3 -c "import hpack; print(hpack.__version__)"
⚠️ Transitive Exposure

You may pull in hpack indirectly through HTTP/2-capable libraries such as hyper, h2, or anything built on them. Run pip show hpack and audit your dependency tree — the vulnerable copy is often a transitive dependency you never installed directly.

Affected Versions

Every release of the HPACK codec before 2.3.0 is affected, along with any client that bundled it.

PackageAffected VersionsFixed In
hpack (Python)1.0.0 – 2.2.02.3.0
hyper (Python)< 0.6.00.6.0

Technical Details

The attack abuses three properties of HPACK working together:

  1. The dynamic table — HPACK keeps a per-connection table of previously seen header fields. Each entry can be referenced by a single-byte index in later requests.
  2. Index references are tiny — One byte on the wire can expand into a full, arbitrarily large header field on decode.
  3. No output cap — Before 2.3.0 the decoder placed no ceiling on the total decompressed size of a header block.
The Flaw

The attacker inserts a single header field sized to exactly fill the dynamic header table, then sends a header block consisting of nothing but repeated references to that one entry. Each one-byte reference re-expands the maximum-size field. A roughly 16 kB block of these references decompresses to about 64 MB. Send a few such blocks and the process is forced to allocate gigabytes of memory — there is no limit to stop it, so the process is OOM-killed.

  • HTTP/2 API servers — Any endpoint terminating HTTP/2 with the affected codec
  • Reverse proxies & gateways — Python-based edge services decoding client headers
  • HTTP/2 clients — A malicious server can bomb a vulnerable client just as easily
  • Microservice meshes — One compromised hop can DoS downstream HTTP/2 peers

Verify Your Version

Terminal
pip show hpack | grep -i version
# Vulnerable if below 2.3.0

Reference: hpack >= 2.3.0 enforces SETTINGS_MAX_HEADER_LIST_SIZE

How to Fix

1Upgrade the Library

Version 2.3.0 added support for SETTINGS_MAX_HEADER_LIST_SIZE, which caps the maximum decompressed size of a header block (default 64 kB, user-configurable). Upgrade to 2.3.0 or later.

pip
pip install --upgrade 'hpack>=2.3.0'
Pinned client (hyper)
pip install --upgrade 'hyper>=0.6.0'

2Set an Explicit Header-List Limit

After upgrading, set a header-list size that matches what your application legitimately needs rather than relying on the default. Anything beyond it is rejected before decompression runs away:

Python
from hpack import Decoder

decoder = Decoder()
# Reject any header block that decompresses past 64 kB
decoder.max_header_list_size = 64 * 1024

What breaks? Nothing, for normal traffic. Legitimate header blocks are kilobytes at most. The limit only trips on pathological inputs — i.e. the attack.

3Defense in Depth at the Edge

If you cannot upgrade every service immediately, terminate HTTP/2 at a hardened reverse proxy that enforces its own header limits, and cap per-connection memory for the application process:

systemd unit
# Bound the worst case so a bomb can't take the host down
[Service]
MemoryMax=512M
MemoryHigh=384M

Critical: Restart Workers

Upgrading the package is not enough — long-running workers keep the old code loaded in memory. Restart every process that imports hpack after upgrading.

Disclosure Timeline

2016-08-03
Imperva publishes HTTP/2 analysis describing the HPACK Bomb
2016-08-04
CVE-2016-6581 assigned; hpack 2.3.0 released with the fix
2016-08-04
hyper 0.6.0 ships the patched HPACK codec
2017-01-10
Entry published in the National Vulnerability Database