Code change:
8.2.1. <del> HPACK is capable of carrying field names or values that are not valid in HTTP.  Though HPACK can carry any octet, fields are not valid in the following cases: </del> <ins> The definitions of field names and values in HTTP prohibits some characters that HPACK might be able to convey.  HTTP/2 implementations SHOULD validate field names and values according to their definitions in Sections HTTP and HTTP respectively and treat messages that contain prohibited characters as malformed. Failure to validate fields can be exploited for request smuggling attacks.  In particular, unvalidated fields might enable attacks when messages are forwarded using HTTP11, where characters such as CR and COLON are used as delimiters.  Implementations that do not fully validate field names and values MUST perform the following minimal validation: </ins> A request or response that contains a field that violates any of these conditions MUST be treated as malformed.  In particular, an

Related discussion:
text: But if we nomarlize that, we are putting in jeopardy all existing code written to HTTP semantics that may not even be aware of the version of HTTP carrying the fields that they are interpretting. Surely there is some other way to allow h2 framing to be used to carry non-HTTP streams without putting all existing HTTP code at risk? If we don't want developers abusing the current protocol, then give them a proper solution for their use-case rather than corrupt the existing primary use-case.
They should represent the exact same level of risk as having the same code parse HTTP/1. But actually that might in fact be what we're all seeking without precisely realizing it, which is making sure an H2 message can be at least reconstructed as an H1 message that is safe to parse. The rules on CR/LF precisely have always been a concern to all of us for this. Same as above. This is always difficult to say if we'd try to extend what HTTP permits. However we're certain that some will almost always be dangerous along a chain or cause parsing issues even inside implementations. Not exactly. This is actually the current situation probably because some consider that the effort needed to comply with the rules in semantics is too high for little value the this level. This is something I can understand. For example in haproxy we have a semantics layer which performs a lot of controls, deduplicates content-length, checks Host against etc. But at the lowest level it is difficult to enforce such checks when you're just converting header lists to internal messages. However we already have the NUL/CR/LF checks that allows the upper layer parser to proceed (the initial implementation used to build an H1 message but that's no longer the case). Thus maybe we should replace all this with an approach centered around this tricky HTTP/1 translation, which also does not infer how implementations should work internally nor suggest to put anything non-HTTP inside HEADERS frames: Just to be clear, I really do not want to see HEADERS frame being abused to carry non-HTTP because I know pretty well what it's like to be an intermediary developer whose product is pointed the finger at for breaking stuff when inserted in a working but non-compliant chain. This is also why I would like to see the SHOULD reject as malformed.