
Nginx Leaves Dynamic Tables Unused in HTTP/2 and HTTP/3 Responses
Nginx implements one-way header compression for both HTTP/2 and HTTP/3: clients compress repeated headers using HPACK or QPACK dynamic tables, but the server never writes to its own dynamic table when sending responses. Code analysis of release-1.31.3 shows every call to ngx_http_v3_encode_field_ri and ngx_http_v3_encode_field_lri passes dynamic=0, and the server encoder stream (NGX_HTTP_V3_STREAM_SERVER_ENCODER) is never created. The same pattern exists in the HPACK filter module, which explicitly sends a table-size update of zero and never calls ngx_http_v2_hpack_t structures. The receiving side fully supports dynamic tables up to the default 4096-byte limit and correctly processes insertions from clients such as aioquic. This asymmetry is permitted by RFC 9204 §4.2 yet removes the compression benefit the binary protocols were designed to provide. The unused encoder path contributed to a use-after-free vulnerability (CVSS 9.2) discovered earlier this year in the QPACK decoder.
HabrAug 14, 2026Translated from Russian