Skip to main content

Never-Indexed Literals

HPACKRFC 7541

HPACK's never-indexed literal representation (type 0x10) instructs the receiver to never add the header to the dynamic table, even if the receiver is proxying the connection and re-encoding headers for an upstream. This is a security signal for sensitive header values like cookies, authorization tokens, and passwords. Intermediaries MUST honor the never-indexed bit and forward it unchanged when re-encoding.

Details

HPACK provides three literal header representations differing in dynamic table behavior:

Literal with Incremental Indexing (0x40): Add to dynamic table. Reduces future requests to a single byte. Used for headers that repeat often.

Literal without Indexing (0x00): Do not add to dynamic table. Used for headers that vary on every request (unique IDs, timestamps) or that the encoder chooses not to index.

Literal Never Indexed (0x10): Do not add to dynamic table AND signal to all intermediaries that this header MUST NOT be indexed in any dynamic table during forwarding. The bit is sticky: a proxy re-encoding headers MUST preserve the never-indexed representation for these headers.

Security motivation: CRIME attack (2012) demonstrated that TLS-compressed headers could leak secret values through adaptive compression side-channels. If an attacker could inject controlled text near a secret header and observe ciphertext length changes, they could recover the secret byte by byte. Never-indexed literals prevent this: even if TLS compression is used (it is disabled in modern TLS implementations), the never-indexed bit prevents the header from being added to a shared table where its length could be compared across requests.

Practical use: Well-implemented HTTP/2 clients and servers should use never-indexed for: cookies with session tokens, Authorization: Bearer headers, any header whose value is a secret the compression oracle could leak.

HTTP/2 prohibits TLS compression: RFC 9113 §9.2 and the TLS ALPN negotiation for h2 prohibit TLS compression (via the TLS Record Layer) for HTTP/2. This largely mitigates CRIME for HTTP/2. The never-indexed bit remains important for defense-in-depth and for scenarios where an intermediary re-encodes headers over a different connection.

Wire example

HEADERS frame encoding
# Never-indexed literal: Authorization header (MUST NOT be added to any dynamic table)
# Representation starting with 0x10:
10              # 0x10 = Literal Header Field Never Indexed, new name
0d              # name length = 13
61 75 74 68 6f 72 69 7a 61 74 69 6f 6e  # "authorization"
22              # value length = 34
42 65 61 72 65 72 20 74 6f 6b 65 6e 31 32 33 ...  # "Bearer secrettoken123"
# Result: sent on the wire, NEVER stored in dynamic table
# A proxy MUST forward this with the 0x10 representation intact

# Contrast: literal WITHOUT indexing (0x00) -- not stored but NOT signaled as never-index
00              # 0x00 = Literal Header Field without Indexing, new name
...             # proxy MAY choose to index this header in its own dynamic table

See Also