Code change:
This simplifies the CORS processing language in the doc, leaving all of the client-side readability processing to fetch and clearly spelling out the server responsibilities.
The new language is much better, but I think it still misses the point. We don't need to be shy about why these requirements are in the spec and under what circumstances they are necessary. I suggest starting with an explanation:
Thanks. I pulled in your explanation and tweaked the language to make it clear that precautions should be considered, one of which may be to not use dictionary-based content encoding. I like the new version a lot better as it allows for cacheable, public data to still use dictionary compression even if it is fetched in a cross-origin context and isn't client-readable. I'll have to be careful with the fetch language as, currently, the client will fail a cross-origin non-readable response in case the server hasn't applied relevant protections. It may be reasonable to relax that and allow for the client to process it and put the burden on the server but it might also let a weak configuration go unnoticed (though since attacker-controlled dictionary content isn't particularly practical in this model, maybe it's not really a concern).
For the existing draft, there is a lot of unnecessary confusion regarding features of fetch, like CORS, that don't make any sense from a security perspective. That's not what CORS is capable of covering, nor how it is implemented in practice, so reusing it doesn't make any sense. cc NAME Moved from private ID
CORS covers privacy from a browser perspective as far as the readability of responses relative to the origin of the containing document which is exactly the context that it is needed for here. The concern that it takes care of is to make sure that responses that shouldn't be readable from the document context of the client can't be exposed to oracle timing attacks (because there won't be any client-opaque responses). HTTP itself doesn't really have the same document framing context and need for protecting read access of individual responses on a shared connection by clients running in different document contexts.
From NAME I still don't see how CORS applies to the draft. If the origin is choosing both the available dictionaries and whether or not to apply them to a given response, why is the context of a request relevant to the nature or credibility of the compressed response? Neither one is controlled by the context. The origin server isn't going to attack itself. The client might choose not to advertise an available dictionary based on the context, but I don't see how ignoring a server's valid response makes a difference. I assume the content of the response after decompressions would still be restricted by CORS, but that should already be defined by fetch; I wouldn't expect this document to specify it.
The concern raised by the security team is that a client could abuse dictionary compression and a timing attack to expose the contents of a CORS-opaque response. The contents themselves would already be prevented from being exposed directly but there's a theoretical risk that an origin serving private data through dictionary compression could expose that data unexpectedly in a cross-origin timing attack. I don't know enough about the practicality of timing-based oracle attacks using dictionary compression and the level of control that an attacker would need to have on either the payload of the response or the payload of the dictionary but in an abundance of caution we are recommending that servers avoid the problem entirely and don't use dictionaries in cross-origin opaque responses (even if it would be blocked from being processed in the client).
The shared-brotli draft has a fairly good write-up on the CRIME attack concerns which is what the CORS mitigations prevent (by making sure there is no mix of public and private data and only allowing for public data): URL Most of the CORS protections are on the client side and not something that needs to be exposed to HTTP or for origins to be concerned about. If a server never mixes public and private data or doesn't talk to a client that needs to partition that kind of data (i.e. not serving to a browser) then it can also ignore the one remaining case called out in the spec. If there's a chance that public/private data will me mixed AND the server is serving content to a browser (or other client that implements CORS) then there is a risk of a timing attack being able to reveal the private content if the crossorigin not-allowed case uses dictionary compression.
Closing this as the need for CORS for the client protection should be well documented at this point (and mostly applies to the WHATWG side of things in fetch processing but there is one case here where people should at least be aware of a possible attack vector if not handled).
I have no problem with this being a requirement for the fetch implementation (or for script-enabled browser implementations in general). However, I still don't understand how the requirements in 9.3.2.* will pass muster for the IESG and RFC Ed reviews without a normative reference to the Fetch spec. A link to a web page isn't enough. Personally, I think these details should be moved to the fetch spec (where the right people will read it). The bits needed for the IETF are covered in 9.3.1 and the first two paragraphs of 9.3.2: and then everything else in 9.3 (and below) can be a replaced by a non-normative reference to fetch. Otherwise, this should be a normative reference and the several links to fetch replaced with an appropriate [FETCH] entry in 11.1.
To be clear, I don't object to moving forward with this as is, but I don't believe will be allowed as is, unless the chairs have some extra special hand-waving skills I haven't seen yet.
I almost take that as a challenge...
There is processing model stuff that is browser-specific that will be in fetch but the parts in 9.3.2.1 and 9.3.2.2 are the things that are required from any HTTP server that might be used to serve sensitive information to a browser. I stripped out as much as I could but there is a timing attack that can be performed in fetching cross-origin content that would allow a client to "read" the response even if it doesn't have access to it on the client side and the only way to prevent it entirely is to not serve a response in the first place. By making it only a requirement when the CORS headers are present, it allows servers that never talk to browsers to not have to consider it but it really does need to be considered carefully for any server that might serve responses to a browser (or anything else that implements cross-origin readability restrictions). Making the protection non-normative would make the privacy protections optional and risk servers not being aware or necessarily implementing it (and it is the same side-channel timing attack that killed SDCH). If we're comfortable making that change then I can make the fetch spec parts authoritative about the CORS restrictions on both clients and servers but it would probably have to be a normative reference.
Oh, I see, the server description contains things a server MUST do (or not do) based on the values received in those fields when they indicate a cross-origin request. I was reading them as things a client would verify after receipt of the Response, since we usually don't rely on a bad client sending "I'm good" information in request header fields. [BTW, this is why the main HTTP specs always target requirements to a role instead of making them neutral requirements on a message.] In that case, these are definitely normative requirements, similar to conditional requests. HTTP servers don't normally parse CORS header fields, since pre-flights and such are handled by back-end applications (not httpd).
I'll make another pass over the CORS language tomorrow to make it clearer and make sure it only covers the parts that servers need to handle for fetch-compliant clients. The client bits can and should be in fetch.

Related discussion:
text: origin and passes the CORS check (https://fetch.spec.whatwg.org/#cors-check). <del> 9.3.2.1. </del> <ins> 9.3.3. </ins> <del> On the client-side, same-origin determination is defined in the fetch spec (https://html.spec.whatwg.org/multipage/browsers.html#origin). </del> <ins> As with any usage of compressed content in a secure context, a potential timing attack exists if the attacker can control any part of the dictionary, or if it can read the dictionary and control any part of the content being compressed, while performing multiple requests that vary the dictionary or injected content.  Under such an attack, the changing size or processing time of the response reveals information about the content, which might be sufficient to read the supposedly secure response. </ins> <del> On the server-side, a request with a "Sec-Fetch-Site:" request header with a value of "same-origin" is to be considered a same-origin request. </del> <ins> In general, a server can mitigate such attacks by preventing variations per request, as in preventing active use of multiple dictionaries for the same content, disabling compression when any portion of the content comes from uncontrolled sources, and securing access and control over the dictionary content in the same way as the response content.  In addition, the following requirements on a server are intended to disable dictionary-aware compression when the client provides CORS request header fields that indicate a cross- origin request context. </ins> <del> For any request that is same-origin: </del> <ins> The following algorithm will return FALSE for cross-origin requests where precautions such as not using dictionary-based compression should be considered: </ins> <del> Response MAY be used as a dictionary. </del> <ins> If there is no "Sec-Fetch-Site" request header then return TRUE. </ins> <del> Response MAY be compressed by an available dictionary. </del> <ins> if the value of the "Sec-Fetch-Site" request header is "same- origin" then return TRUE. </ins> <del> 9.3.2.2. </del> <ins> If there is no "Sec-Fetch-Mode" request header then return TRUE. </ins> <del> For requests that are not same-origin (same-origin), the "mode" of the request can be used to determine the readability of the response. </del> <ins> If the value of the "Sec-Fetch-Mode" request header is "navigate" or "same-origin" then return TRUE. </ins> <del> For clients that conform to the fetch spec, the mode of the request is stored in the RequestMode attribute of the request (https://fetch.spec.whatwg.org/#requestmode). </del> <ins> If the value of the "Sec-Fetch-Mode" request header is "cors": </ins> <del> For servers responding to clients that expose the request mode information, the value of the mode is sent in the "Sec-Fetch-Mode" request header. </del> <ins> If the response does not include an "Access-Control-Allow- Origin" response header then return FALSE. </ins> <del> If a "Sec-Fetch-Mode" request header is not present, the server SHOULD allow for the dictionary compression to be used. </del> <ins> If the request does not include an "Origin" request header then return FALSE. </ins> <del> If the mode is "navigate" or "same-origin": </del> <ins> If the value of the "Access-Control-Allow-Origin" response header is "*" then return TRUE. </ins> <del> Response MAY be used as a dictionary. </del> <ins> If the value of the "Access-Control-Allow-Origin" response header matches the value of the "Origin" request header then return TRUE. </ins> <del> Response MAY be compressed by an available dictionary. If the mode is "cors": For clients, apply the CORS check from the fetch spec (https://fetch.spec.whatwg.org/#cors-check) which includes credentials checking restrictions that may not be possible to check on the server. If the CORS check passes: Response MAY be used as a dictionary. Response MAY be compressed by an available dictionary. Else: Response MUST NOT be used as a dictionary. Response MUST NOT be compressed by an available dictionary. For servers: If the response does not include an "Access-Control-Allow- Origin" response header: Response MUST NOT be used as a dictionary. Response MUST NOT be compressed by an available dictionary. If the request does not include an "Origin" request header: Response MUST NOT be used as a dictionary. Response MUST NOT be compressed by an available dictionary. If the value of the "Access-Control-Allow-Origin" response header is "*": Response MAY be used as a dictionary. Response MAY be compressed by an available dictionary. If the value of the "Access-Control-Allow-Origin" response header matches the value of the "Origin" request header: Response MAY be used as a dictionary. Response MAY be compressed by an available dictionary. If the mode is any other value (including "no-cors"): Response MUST NOT be used as a dictionary. Response MUST NOT be compressed by an available dictionary. </del> <ins> return FALSE. </ins> 10.