| Internet-Draft | PMCE State After Refused Messages | August 2026 |
| Srivastava | Expires 14 February 2027 | [Page] |
RFC 7692 defines Per-Message Compression Extensions for the WebSocket Protocol, including the "permessage-deflate" extension. When context takeover is in effect, the LZ77 sliding window is retained across messages, so the decompression of one message can depend on the plaintext of earlier messages.¶
RFC 7692 does not state what the sliding window contains after a message has been successfully decompressed but subsequently refused by a check applied to the decompressed plaintext, such as UTF-8 validation, a payload size limit, or an application-level policy. An implementation that retains the refused plaintext in the window violates no stated requirement, yet the content of a refused message can then influence the decompression of a later message that is accepted.¶
This document describes the gap, contrasts it with the corresponding situation in QPACK where RFC 9204 specifies the required behavior, and recommends behavior for implementations. It defines no new protocol element and updates no existing specification.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 14 February 2027.¶
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
The "permessage-deflate" extension defined in [RFC7692] compresses WebSocket message payloads using DEFLATE [RFC1951]. Unless "no_context_takeover" has been negotiated, the LZ77 sliding window persists across messages on a connection. This is the behavior that makes the extension effective: repeated content across messages compresses well precisely because the window retains earlier plaintext.¶
Retaining state across messages means the interpretation of one message can depend on the content of earlier ones. A back-reference in a later message resolves against whatever the window currently holds.¶
Implementations commonly apply checks to the decompressed plaintext after decompression has completed. UTF-8 validity for text messages is required by [RFC6455]. Payload size limits are common in deployment. Applications frequently apply their own content policy. When such a check refuses a message, decompression has already succeeded and the plaintext is already in the window.¶
[RFC7692] does not say what the window should contain at that point. This document describes that gap and its consequences, and recommends behavior.¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.¶
This document uses "refused message" to mean a message whose payload was successfully decompressed by the extension, and which was then rejected by a check applied to the decompressed plaintext. A message that fails to decompress is not a refused message in this sense.¶
Section 7.1.1.1 of [RFC7692] describes the "server_no_context_takeover" extension parameter, and Section 7.1.1.2 describes "client_no_context_takeover". Absent these parameters, an endpoint retains the LZ77 sliding window across messages.¶
Section 7.2.2 of [RFC7692] describes decompression and the conditions under which the sliding window is reset. The specification is written in terms of successful message processing and of decompression failure. It does not address the case where decompression succeeds and the message is refused afterwards.¶
Consider a connection with context takeover in effect:¶
At no point in this sequence does an implementation violate a stated requirement of [RFC7692]. Retaining the plaintext of a refused message in the window is neither required nor forbidden.¶
The consequence is that a check applied to decompressed plaintext does not, on its own, prevent that plaintext from reaching the application. It prevents delivery of the message that carried it. The content remains available to be reproduced by a subsequent message that the same check accepts.¶
Implementations vary in how they handle this case, and the variation does not appear to be the result of differing interpretations of [RFC7692]. It appears to result from properties of the surrounding implementation.¶
Some implementations terminate the connection whenever a post-decompression check fails. In those implementations the sequence in Section 3.2 cannot complete, because there is no connection on which message B could arrive. The compression context is not reset; it simply becomes unreachable.¶
Other implementations allow a post-decompression check to fail without terminating the connection, either by default or under a configuration option. In those implementations the sequence can complete.¶
The distinction that determines the outcome is therefore the connection lifecycle policy of the surrounding implementation, not any property of the compression extension. An implementation that is safe for this reason may cease to be safe if its termination behavior is made configurable, or if its compression codec is exposed as an interface that other software drives directly.¶
A related concern was raised against one implementation in a public issue report [NETTY6209], which discusses the state of the compression context following an error. The general question of what the window should contain after a refused message does not appear to have been treated in the specification.¶
QPACK [RFC9204] presents a structurally similar hazard. The dynamic table persists across field sections on a connection, so the interpretation of one field section can depend on earlier ones. If a field section were refused after decoding, and the dynamic table retained its effects, a later accepted field section could reference entries derived from the refused one.¶
Section 6 of [RFC9204] addresses this directly. It specifies that certain decoding failures MUST be treated as connection errors of the relevant type. The result is that a QPACK implementation cannot continue on a connection whose decoder state is in question, because the specification does not permit it to.¶
The two cases are worth stating side by side:¶
The difference in outcome between implementations of the two protocols appears to follow from this difference in what the specifications require, rather than from differences in implementation quality.¶
The following recommendations are addressed to implementers of [RFC7692] and to applications built on it. They are stated as recommendations rather than as updates to [RFC7692]; this document does not update that specification.¶
When a message is refused by a check applied to its decompressed plaintext, an implementation SHOULD do one of the following:¶
The first option is what several implementations already do as a consequence of their error handling. Making it an explicit consequence of the refusal, rather than an incidental one, means the property is preserved if the surrounding error handling changes.¶
An implementation that continues processing a connection after refusing a message, without resetting the window, SHOULD document that behavior, so that applications relying on post-decompression checks are aware that a refused message's content remains referenceable.¶
An implementation that exposes its compression codec as an interface which other software may drive directly, separately from its own connection handling, SHOULD document whether the safety of that codec depends on connection termination performed elsewhere.¶
Software driving such an interface does not necessarily inherit the error handling of the implementation that provides it. A codec whose safety in practice depends on a connection teardown performed by a separate component is not safe when driven without that component.¶
Where an implementation provides a configuration option that suppresses connection termination on protocol violations, the documentation for that option SHOULD state which components the option governs.¶
An option described in general terms as controlling behavior on protocol violations may in practice govern only some of the components that can refuse a message, leaving the compression context outside its scope. An operator selecting such an option is unlikely to infer that from the option's name.¶
The concern described in this document is that a check applied to decompressed plaintext may not have the effect an application expects. Refusing a message prevents its delivery. It does not necessarily prevent its content from being delivered later, inside a message that the same check accepts.¶
Applications that rely on post-decompression validation as a security control should be aware of this. A UTF-8 validity check, a payload size limit, or a content policy applied after decompression constrains which messages are delivered, not which plaintext can reach the application.¶
The severity of this in any particular deployment depends on factors outside the scope of this document, including whether the affected compression context is shared between security principals. In the common case where a WebSocket connection carries traffic for a single client, both the refused and the accepted message originate from that client, and the content that reaches the application is content the client already possessed. In that case the concern is the bypass of a validation control rather than disclosure of information belonging to another party.¶
Implementations that terminate the connection when a message is refused are not affected by the sequence described here, because the affected compression context becomes unreachable. As noted in Section 3.3, this property may be incidental to the implementation's error handling rather than a deliberate defense, and may therefore not survive changes to that error handling.¶
This document has no IANA actions.¶
The comparison with QPACK arose from examining implementations of both protocols side by side. The author thanks the maintainers of the WebSocket and HTTP/3 implementations whose source and issue history made that comparison possible.¶