High chrome Logic Error 🔧 Commit mapped

Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactIncorrect authorization in Network
DescriptionIncorrect authorization in Network
ComponentNetwork
Bug ClassLogic Error
Tracker553118043
Fix commit4568e184333b (chromium/src) +40/-0
CISA KEVNot listed
CreditedGoogle
Disclosed2026-09-08

Background

`IsRequestHeaderSafe`
the services/network allowlist check that decides whether a renderer-supplied HTTP request header name/value pair may be sent on a network request.
Shared dictionary compression
a net-stack feature where responses are compressed against a previously fetched dictionary, negotiated via the dcb (shared Brotli) and dcz (shared Zstd) Accept-Encoding tokens.
`Accept-Encoding` header
a request header, legitimately set by the media pipeline (e.g. identity;q=1, *;q=0), that advertises which content encodings the client will accept.
`net::HttpUtil::ValuesIterator`
a helper that splits a comma-separated header value into individual tokens for per-value inspection.

Root Cause Analysis

IsRequestHeaderSafe in services/network/public/cpp/header_util.cc validated several sensitive request headers but placed no restriction on the encoding tokens a renderer could put in Accept-Encoding, even though shared dictionary compression is meant to be 100% managed by the network service and net stack. The violated invariant is that the renderer must never influence shared-dictionary negotiation, since the network stack alone knows whether a valid dictionary and the feature are actually available. Because the header passed through unchecked, a renderer could inject dcb or dcz tokens and advertise shared dictionary compression on requests where it was not really enabled, an incorrect-authorization condition where an untrusted process drives a decision reserved for a trusted one.

The fix iterates each comma-separated Accept-Encoding value with net::HttpUtil::ValuesIterator and rejects the header (return false) if any token starts with kSharedBrotliContentEncodingName or kSharedZstdContentEncodingName, while still permitting ordinary values like gzip and the media pipeline’s identity;q=1, *;q=0. This restores the boundary by making the trusted network stack the sole party that may add those tokens.

Key insight
The single mistake was trusting the renderer’s Accept-Encoding value wholesale, letting it advertise shared-dictionary encodings that only the network stack is authorized to negotiate; the fix closes this by explicitly filtering dcb/dcz tokens out of renderer-provided Accept-Encoding headers.

Attack Path

  1. Compromised renderer An attacker who controls a renderer process crafts a network request through a path that lets it set the Accept-Encoding request header.
  2. Inject dictionary tokens The renderer inserts dcb or dcz (e.g. gzip, dcb or dcz;q=1) into the value, which IsRequestHeaderSafe previously accepted unchanged.
  3. Advertise unenabled compression The request goes out advertising shared dictionary compression even though the network stack did not enable it or select a dictionary.
  4. Server responds accordingly A server may then negotiate and return a shared-dictionary-compressed response outside the state the trusted net stack expects.

Impact Assessment

An attacker gains the ability, from a compromised or malicious renderer process, to force shared-dictionary encoding tokens (dcb/dcz) into outgoing requests, driving a negotiation the network service is supposed to solely control. The precondition is a renderer able to influence the Accept-Encoding request header on a request handled by the network service. The exposure is an incorrect-authorization/logic flaw in the Network component rather than a demonstrated memory-safety primitive from this diff alone.

Files Changed

  • services/network/public/cpp/header_util.cc
  • services/network/public/cpp/header_util_unittest.cc

Audit Directions

  • Renderer-controlled header allowlists
    Audit every header-safety predicate (like IsRequestHeaderSafe) for encodings, tokens, or directives that a trusted layer negotiates but the allowlist forwards verbatim from an untrusted process.
  • Comma-separated header parsing
    Verify that checks on list-valued headers (Accept-Encoding, Connection, Transfer-Encoding) inspect each token with a proper iterator rather than the raw string, since a single-token match is easy to bypass with prefixes or q-values like dcz;q=1.
  • Trust-boundary-managed features
    Review features documented as fully owned by the network/net stack (shared dictionaries, compression, priority hints) to confirm no renderer-supplied input can toggle or advertise them.
From 4568e184333b8b92b07c135f11b10b3d811d8f36 Mon Sep 17 00:00:00 2001
From: Patrick Meenan <pmeenan@chromium.org>
Date: Thu, 27 Aug 2026 18:42:10 -0700
Subject: [PATCH] Block renderer-provided dcb or dcz Accept-Encoding headers

Dictionary compression is 100% handled in the network service and net
stack. This makes sure that renderer's don't accidentally try to
advertise dictionary compression when it's not really enabled.

Bug: 553118043
Change-Id: If9cdcf100520e0f74216daa80dc948e0f397748f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8300933
Commit-Queue: Patrick Meenan <pmeenan@chromium.org>
Reviewed-by: Tsuyoshi Horo <horo@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1687719}
---

diff --git a/services/network/public/cpp/header_util.cc b/services/network/public/cpp/header_util.cc
index 402042a..a06abd25 100644
--- a/services/network/public/cpp/header_util.cc
+++ b/services/network/public/cpp/header_util.cc
@@ -18,6 +18,7 @@
 #include "net/http/http_response_headers.h"
 #include "net/http/http_status_code.h"
 #include "net/http/http_util.h"
+#include "net/shared_dictionary/shared_dictionary_constants.h"
 #include "services/network/public/cpp/cors/cors.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/mojom/url_response_head.mojom.h"
@@ -75,6 +76,26 @@
       return false;
   }
 
+  // The Accept-Encoding header can be set by the media pipeline (e.g.
+  // "identity;q=1, *;q=0"), but must not be used to negotiate shared
+  // dictionary compression (dcb, dcz) which is managed by the network stack.
+  if (base::EqualsCaseInsensitiveASCII(
+          key, net::HttpRequestHeaders::kAcceptEncoding)) {
+    net::HttpUtil::ValuesIterator encodings(value, ',');
+    while (encodings.GetNext()) {
+      if (base::StartsWith(
+              encodings.value(),
+              net::shared_dictionary::kSharedBrotliContentEncodingName,
+              base::CompareCase::INSENSITIVE_ASCII) ||
+          base::StartsWith(
+              encodings.value(),
+              net::shared_dictionary::kSharedZstdContentEncodingName,
+              base::CompareCase::INSENSITIVE_ASCII)) {
+        return false;
+      }
+    }
+  }
+
   // The Connection header is a comma-separated list of tokens. Per RFC 9110
   // section 7.6.1, intermediaries treat each listed token as the name of a
   // header to remove before forwarding, so only allow the connection-management
diff --git a/services/network/public/cpp/header_util_unittest.cc b/services/network/public/cpp/header_util_unittest.cc
index 9d2adf4..f4635e2 100644
--- a/services/network/public/cpp/header_util_unittest.cc
+++ b/services/network/public/cpp/header_util_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/strings/stringprintf.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_response_headers.h"
+#include "net/shared_dictionary/shared_dictionary_constants.h"
 #include "services/network/public/cpp/features.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -28,6 +29,15 @@
       {"Upgrade", "webbedsocket", false},
       {"hOsT", "foo.test", false},
 
+      {net::HttpRequestHeaders::kAcceptEncoding, "gzip", true},
+      {net::HttpRequestHeaders::kAcceptEncoding, "identity;q=1, *;q=0", true},
+      {net::HttpRequestHeaders::kAcceptEncoding, "gzip, identity;q=1, *;q=0",
+       true},
+      {net::HttpRequestHeaders::kAcceptEncoding, "dcb", false},
+      {net::HttpRequestHeaders::kAcceptEncoding, "dcz", false},
+      {net::HttpRequestHeaders::kAcceptEncoding, "gzip, dcb", false},
+      {net::HttpRequestHeaders::kAcceptEncoding, "dcz;q=1", false},
+
       {net::HttpRequestHeaders::kConnection, "Upgrade", false},
       {net::HttpRequestHeaders::kConnection, "Close", true},
       {net::HttpRequestHeaders::kConnection, "keep-alive", true},
@@ -92,6 +102,15 @@
       {net::HttpRequestHeaders::kTransferEncoding, "gzip", false},
       {"Set-Cookie", "foo=bar", false},
 
+      {net::HttpRequestHeaders::kAcceptEncoding, "gzip", true},
+      {net::HttpRequestHeaders::kAcceptEncoding, "identity;q=1, *;q=0", true},
+      {net::HttpRequestHeaders::kAcceptEncoding, "gzip, identity;q=1, *;q=0",
+       true},
+      {net::HttpRequestHeaders::kAcceptEncoding, "dcb", false},
+      {net::HttpRequestHeaders::kAcceptEncoding, "dcz", false},
+      {net::HttpRequestHeaders::kAcceptEncoding, "gzip, dcb", false},
+      {net::HttpRequestHeaders::kAcceptEncoding, "dcz;q=1", false},
+
       {net::HttpRequestHeaders::kConnection, "Upgrade", false},
       {net::HttpRequestHeaders::kConnection, "Close", true},
       {net::HttpRequestHeaders::kConnection, "keep-alive", true},
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/services/network/public/cpp/header_util_unittest.cc b/services/network/public/cpp/header_util_unittest.cc
index 9d2adf4..f4635e2 100644
--- a/services/network/public/cpp/header_util_unittest.cc
+++ b/services/network/public/cpp/header_util_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/strings/stringprintf.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_response_headers.h"
+#include "net/shared_dictionary/shared_dictionary_constants.h"
 #include "services/network/public/cpp/features.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -28,6 +29,15 @@
       {"Upgrade", "webbedsocket", false},
       {"hOsT", "foo.test", false},
 
+      {net::HttpRequestHeaders::kAcceptEncoding, "gzip", true},
+      {net::HttpRequestHeaders::kAcceptEncoding, "identity;q=1, *;q=0", true},
+      {net::HttpRequestHeaders::kAcceptEncoding, "gzip, identity;q=1, *;q=0",
+       true},
+      {net::HttpRequestHeaders::kAcceptEncoding, "dcb", false},
+      {net::HttpRequestHeaders::kAcceptEncoding, "dcz", false},
+      {net::HttpRequestHeaders::kAcceptEncoding, "gzip, dcb", false},
+      {net::HttpRequestHeaders::kAcceptEncoding, "dcz;q=1", false},
+
       {net::HttpRequestHeaders::kConnection, "Upgrade", false},
       {net::HttpRequestHeaders::kConnection, "Close", true},
       {net::HttpRequestHeaders::kConnection, "keep-alive", true},
@@ -92,6 +102,15 @@
       {net::HttpRequestHeaders::kTransferEncoding, "gzip", false},
       {"Set-Cookie", "foo=bar", false},
 
+      {net::HttpRequestHeaders::kAcceptEncoding, "gzip", true},
+      {net::HttpRequestHeaders::kAcceptEncoding, "identity;q=1, *;q=0", true},
+      {net::HttpRequestHeaders::kAcceptEncoding, "gzip, identity;q=1, *;q=0",
+       true},
+      {net::HttpRequestHeaders::kAcceptEncoding, "dcb", false},
+      {net::HttpRequestHeaders::kAcceptEncoding, "dcz", false},
+      {net::HttpRequestHeaders::kAcceptEncoding, "gzip, dcb", false},
+      {net::HttpRequestHeaders::kAcceptEncoding, "dcz;q=1", false},
+
       {net::HttpRequestHeaders::kConnection, "Upgrade", false},
       {net::HttpRequestHeaders::kConnection, "Close", true},
       {net::HttpRequestHeaders::kConnection, "keep-alive", true},
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.