Never-Indexed Literals
HPACKRFC 7541HPACK'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
# 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