Skip to content

fix: use HeaderMap::try_append to prevent panics on absurd amounts of headers#909

Merged
seanmonstar merged 2 commits into
hyperium:masterfrom
imlk0:fix/headermap-dos-panic
Jun 9, 2026
Merged

fix: use HeaderMap::try_append to prevent panics on absurd amounts of headers#909
seanmonstar merged 2 commits into
hyperium:masterfrom
imlk0:fix/headermap-dos-panic

Conversation

@imlk0

@imlk0 imlk0 commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Replace HeaderMap::append() with HeaderMap::try_append() in the HPACK decode callback (src/frame/headers.rs:914) to prevent a remote DoS.

Problem

An unauthenticated remote client can crash any h2-based server by sending a single HTTP/2 request with >24,576 unique header fields. HeaderMap::append() panics with "size overflows MAX_SIZE" when its internal hash table capacity is exceeded — this is a process-level panic that terminates all connections.

  • max_header_list_size default is 16 MB, which allows ~524,288 headers at 32 bytes each
  • But HeaderMap panics at 24,576 unique keys — more than 20× below the configured budget
  • Attack cost: ~500 KB wire data

Fix

- self.fields.append(name, value);
+ if let Err(_) = self.fields.try_append(name, value) {
+     self.is_over_size = true;
+ }

When is_over_size is set, the existing logic in proto/streams/recv.rs:204 handles the error at the stream level (RST_STREAM / HTTP 431), keeping the connection alive.

Impact

Before Full process crash (panic)
After Stream-level rejection (RST_STREAM / 431)
Attack cost ~500 KB, 24,600 unique headers
Breaking None

https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=1afcbbde1795302003479d26e0b2801f

@0x676e67

0x676e67 commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

We've encountered this issue in production as well.

@imlk0

imlk0 commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

We've encountered this issue in production as well.

Thanks for confirming this! It's incredibly valuable to know that this is being encountered in real-world production environments and is not just a theoretical edge case.

I actually stumbled upon this panic vector while doing research on CVE-2026-53948 (the HPACK / HTTP/2 Bomb vulnerability class).

Since you are running h2 in production, I would love to hear your thoughts on CVE-2026-53948. Do you think h2 in its current state is vulnerable to this attack?

@0x676e67

0x676e67 commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

We've encountered this issue in production as well.

Thanks for confirming this! It's incredibly valuable to know that this is being encountered in real-world production environments and is not just a theoretical edge case.

I actually stumbled upon this panic vector while doing research on CVE-2026-53948 (the HPACK / HTTP/2 Bomb vulnerability class).

Since you are running h2 in production, I would love to hear your thoughts on CVE-2026-53948. Do you think h2 in its current state is vulnerable to this attack?

I'm not familiar with CVE-2026-53948 for now; I suggest adding a test in this PR to verify the fix works.

@seanmonstar

Copy link
Copy Markdown
Member

The HPACK bomb is something different. It hopes to decode small wire payloads into tons of memory and OOMKill the process. h2 enforces max size limits.

What you've triggered is a different case, simply a hard limit on the number of header fields the HeaderMap supports, and panicking once hit. The panic should be fixed. Just needs the minimum version of http increased to when try_append was added.

Though, there's a few other things that protect a server from this:

  • The vast majority of server use Tokio, or something similar, which confine panics to the async task. So it won't kill the process, just that connection task. That connection is likely just your own connection, so any other streams in most cases are just your own other streams.
  • The h2 crate itself is a building block, it doesn't define a lot of settings that a production server should pick. For example, hyper, when depending on h2, has a default max header list size of just 16KB, which is why this doesn't trigger there. Other implementations that use h2 without hyper need to configure reasonable settings.

@imlk0 imlk0 force-pushed the fix/headermap-dos-panic branch from 326b11e to 112730c Compare June 8, 2026 11:31
@imlk0

imlk0 commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

Hi @seanmonstar, this pr is ready to review now. And here's a summary of the changes:

  1. Bump minimum http dep to 1.1 since HeaderMap::try_append was added in http 1.1.0. The minimal-versions CI resolved http to 1.0.0 which lacks this method.

  2. Added an unit test test_try_append_prevents_panic_on_max_size_reached.

The Test(nightly) failure seems be a pre-existing issue in the repo?

@seanmonstar

Copy link
Copy Markdown
Member

Yea, I'm fixing up any other CI failures. I'm very confused why the cargo fmt job is failing... I don't see that you touched that file, and a local cargo fmt run shows no change. And another PR that I just submitted didn't fail the style check (#910). Very weird...

@seanmonstar

Copy link
Copy Markdown
Member

Oh my bad, I don't know why I didn't notice, the style check is failing something in this PR. If you run cargo fmt, it should fix it up.

imlk0 added 2 commits June 9, 2026 09:41
…S panic

HeaderMap::append() panics when inserting >24,576 unique header fields
(size overflows MAX_SIZE), allowing an unauthenticated remote attacker to
crash the server with a single request containing enough unique headers.

Replace with try_append() and set is_over_size on Err, so the existing
is_over_size check in recv.rs properly rejects the stream (RST_STREAM /
HTTP 431) instead of panicking.
The try_append method was added in http 1.1.0. Without this bump,
the minimal-versions CI job resolves http to 1.0.0 which lacks the
method, causing compilation failure.
@imlk0 imlk0 force-pushed the fix/headermap-dos-panic branch from 8b07825 to ef51cf1 Compare June 9, 2026 01:42
@imlk0

imlk0 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

@seanmonstar I've fixed withcargo fmt, sorry for the oversight

@seanmonstar seanmonstar changed the title fix: prevent DoS panic from HeaderMap capacity overflow (try_append) fix: use HeaderMap::try_append to prevent panics on absurd amounts of headers Jun 9, 2026
@seanmonstar seanmonstar merged commit 4f51fff into hyperium:master Jun 9, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants