Skip to content

Reject connection-specific headers sent via HPACK/QPACK indexed names - #565

Closed
DeagleGross wants to merge 1 commit into
mainfrom
deaglegross/fix-chunked-hpack-indexed-name
Closed

Reject connection-specific headers sent via HPACK/QPACK indexed names#565
DeagleGross wants to merge 1 commit into
mainfrom
deaglegross/fix-chunked-hpack-indexed-name

Conversation

@DeagleGross

Copy link
Copy Markdown
Owner

Summary

Fixes a gap in dotnet#66669. Connection-specific header fields (connection, transfer-encoding, keep-alive, proxy-connection, upgrade, te) were only rejected when sent as an HPACK/QPACK literal name + value. When the header name was sent using an indexed-name representation, the check was skipped.

Concretely, transfer-encoding is entry 57 in the HPACK static table. A request encoding it as Literal Header Field — Indexed Name (index 57) with a literal value chunked was routed through OnStaticIndexedHeader(index, value)HeaderType.StaticAndValue, which never called ValidateHeaderContent, so IsConnectionSpecificHeaderField was never evaluated. This allowed Transfer-Encoding: chunked through on HTTP/2.

HTTP/3 has the same structural gap: QPACK's static table contains no connection-specific header, but an entry inserted into the QPACK dynamic table via the encoder stream (which isn't validated on that path) could then be referenced by a dynamic indexed name (HeaderType.Dynamic), bypassing the same check.

Fix

Move the IsConnectionSpecificHeaderField check out of ValidateHeaderContent and to the top of OnHeaderCore in both Http2Connection and Http3Stream, so it runs for every header representation — fully indexed, indexed-name + literal value, and literal name + value — as well as trailers. The decoded name/value spans are always populated for these callbacks, so no additional decoding is required.

Only connection-specific header fields are affected; no other/legitimate headers change behavior. Headers that were already validated on the literal path behave exactly as before.

Tests

  • Added HEADERS_Received_TransferEncodingWithHPackIndexedName_ConnectionError, which sends a hand-crafted HPACK block referencing transfer-encoding by static index 57 with a literal chunked value and asserts a PROTOCOL_ERROR connection error with HttpErrorConnectionSpecificHeaderField.
  • Existing connection-specific / trailer / header-validation tests still pass (245 filtered tests green).

Refs dotnet#66669.

Connection-specific header fields (e.g. Transfer-Encoding) were only validated on the literal name+value path. Using HPACK's indexed-name representation (transfer-encoding is static table index 57) routed the header through OnStaticIndexedHeader/OnDynamicIndexedHeader, skipping the IsConnectionSpecificHeaderField check and allowing Transfer-Encoding: chunked through on HTTP/2. HTTP/3 shares the same structural gap via QPACK dynamic-table indexed names.

Move the connection-specific header check so it runs for every header representation in both Http2Connection and Http3Stream. No legitimate headers are affected.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@DeagleGross DeagleGross closed this Jul 3, 2026
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.

1 participant