Medium chrome Logic Error 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInformation leak in Extensions
DescriptionInformation leak in Extensions
ComponentExtensions
Bug ClassLogic Error
Tracker533917984
Fix commit77d1561238e8 (chromium/src) +60/-39
CISA KEVNot listed
CreditedOran Simhony from Palo Alto Networks
Disclosed2026-08-25

Changed Functions

FunctionChangeNotes
TEST_F
services/network/public/cpp/cors/cors_unittest.cc
modified
for
services/network/public/cpp/cors/cors_unittest.cc
modified
for
third_party/blink/common/service_worker/service_worker_loader_helpers.cc
modified

Files Changed

  • services/network/public/cpp/cors/cors.cc
  • services/network/public/cpp/cors/cors.h
  • services/network/public/cpp/cors/cors_unittest.cc
  • third_party/blink/common/service_worker/service_worker_loader_helpers.cc
  • third_party/blink/renderer/platform/loader/cors/cors.cc
  • third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
From 77d1561238e8a4d00c5c1068a6daf76dbca12a6f Mon Sep 17 00:00:00 2001
From: Maksim Sisov <[email protected]>
Date: Wed, 15 Jul 2026 05:01:24 -0700
Subject: [PATCH] Add network::cors::IsCorsSafelistedResponseHeaderName

The CORS-safelisted response-header-name list is duplicated in two Blink
copies: the renderer WTF predicate IsCorsSafelistedResponseHeader() and
the blink-common IsCorsExposedResponseHeader() helper. There is no
browser-process-callable primitive for it, which a later change needs.

Add IsCorsSafelistedResponseHeaderName() next to the request-side
safelist predicates in network::cors and fold both Blink copies onto it.
The blink-common copy keeps its content-range media carve-out as an
explicit branch. No behavior change: the renderer set was matched
case-insensitively before and the new predicate lowercases the input.

Bug: 533917984
Change-Id: I41ba7c40c3a4474c21e98bd8be998f538e4f3513
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8084477
Reviewed-by: Kenichi Ishibashi <[email protected]>
Commit-Queue: Maksim Sisov <[email protected]>
Reviewed-by: Daniel Cheng <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1662521}
---

diff --git a/services/network/public/cpp/cors/cors.cc b/services/network/public/cpp/cors/cors.cc
index 14334f7..ec75705 100644
--- a/services/network/public/cpp/cors/cors.cc
+++ b/services/network/public/cpp/cors/cors.cc
@@ -257,6 +257,21 @@
       /*is_ad_auction_trusted_signals_request=*/false);
 }
 
+bool IsCorsSafelistedResponseHeaderName(std::string_view name) {
+  // https://fetch.spec.whatwg.org/#cors-safelisted-response-header-name
+  static constexpr auto kSafelistedResponseHeaderNames =
+      base::MakeFixedFlatSet<std::string_view>({
+          "cache-control",
+          "content-language",
+          "content-length",
+          "content-type",
+          "expires",
+          "last-modified",
+          "pragma",
+      });
+  return kSafelistedResponseHeaderNames.contains(base::ToLowerASCII(name));
+}
+
 bool IsCorsSafelistedHeader(const std::string& name,
                             const std::string& value,
                             bool is_ad_auction_trusted_signals_request) {
diff --git a/services/network/public/cpp/cors/cors.h b/services/network/public/cpp/cors/cors.h
index 8c086d5..6728fb6a 100644
--- a/services/network/public/cpp/cors/cors.h
+++ b/services/network/public/cpp/cors/cors.h
@@ -107,6 +107,12 @@
 bool IsNoCorsSafelistedHeader(const std::string& name,
                               const std::string& value);
 
+// Returns true if `name` is a CORS-safelisted response header name.
+// The match is case-insensitive.
+// https://fetch.spec.whatwg.org/#cors-safelisted-response-header-name
+COMPONENT_EXPORT(NETWORK_CPP)
+bool IsCorsSafelistedResponseHeaderName(std::string_view name);
+
 // https://fetch.spec.whatwg.org/#cors-unsafe-request-header-names
 // |headers| must not contain multiple headers for the same name.
 // The returned list is NOT sorted.
diff --git a/services/network/public/cpp/cors/cors_unittest.cc b/services/network/public/cpp/cors/cors_unittest.cc
index 991dfd7..590471ee1 100644
--- a/services/network/public/cpp/cors/cors_unittest.cc
+++ b/services/network/public/cpp/cors/cors_unittest.cc
@@ -218,6 +218,33 @@
   EXPECT_FALSE(IsCorsSafelistedHeader("user-agent", "foo"));
 }
 
+TEST_F(CorsTest, SafelistedResponseHeaderName) {
+  // The seven CORS-safelisted response header names, in mixed case to exercise
+  // the case-insensitive match.
+  static constexpr std::string_view kSafelisted[] = {
+      "cache-control", "Content-Language", "CONTENT-LENGTH", "content-type",
+      "Expires",       "Last-Modified",    "pragma",
+  };
+  for (std::string_view name : kSafelisted) {
+    SCOPED_TRACE(name);
+    EXPECT_TRUE(IsCorsSafelistedResponseHeaderName(name));
+  }
+
+  // "content-range" is deliberately excluded: it is a media-only carve-out
+  // kept out of the JS-visible safelist. The rest are ordinary non-safelisted
+  // headers.
+  static constexpr std::string_view kNotSafelisted[] = {
+      "content-range",
+      "set-cookie",
+      "x-auth-token",
+      "sec-ch-ua",
+  };
+  for (std::string_view name : kNotSafelisted) {
+    SCOPED_TRACE(name);
+    EXPECT_FALSE(IsCorsSafelistedResponseHeaderName(name));
+  }
+}
+
 TEST_F(CorsTest, SafelistedAccept) {
   EXPECT_TRUE(IsCorsSafelistedHeader("accept", "text/html"));
   EXPECT_TRUE(IsCorsSafelistedHeader("AccepT", "text/html"));
diff --git a/third_party/blink/common/service_worker/service_worker_loader_helpers.cc b/third_party/blink/common/service_worker/service_worker_loader_helpers.cc
index f64bffbc..cf2a042 100644
--- a/third_party/blink/common/service_worker/service_worker_loader_helpers.cc
+++ b/third_party/blink/common/service_worker/service_worker_loader_helpers.cc
@@ -13,7 +13,6 @@
 #include <vector>
 
 #include "base/byte_size.h"
-#include "base/containers/fixed_flat_set.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
 #include "base/strings/to_string.h"
@@ -22,6 +21,7 @@
 #include "net/http/http_util.h"
 #include "net/url_request/redirect_info.h"
 #include "net/url_request/redirect_util.h"
+#include "services/network/public/cpp/cors/cors.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/resource_request_body.h"
 #include "services/network/public/mojom/fetch_api.mojom-shared.h"
@@ -33,30 +33,18 @@
 namespace blink {
 namespace {
 
-// LINT.IfChange(kCorsSafelistedResponseHeaderNames)
-// https://fetch.spec.whatwg.org/#cors-safelisted-response-header-name
-constexpr auto kCorsSafelistedResponseHeaderNames =
-    base::MakeFixedFlatSet<std::string_view>({
-        "cache-control",
-        "content-language",
-        "content-length",
-        // "content-range" is not a standard CORS-safelisted response header,
-        // but it is required by C++ media loaders (e.g. WebMediaPlayer) to
-        // process "206 Partial Content" range responses. We permit it in
-        // URLResponseHead to avoid breaking media playback, while it remains
-        // filtered out and hidden from JavaScript's view in the renderer.
-        "content-range",
-        "content-type",
-        "expires",
-        "last-modified",
-        "pragma",
-    });
-// LINT.ThenChange(third_party/blink/renderer/platform/loader/cors/cors.cc:allowed_cross_origin_response_headers)
-
 bool IsCorsExposedResponseHeader(
     std::string_view name,
     const std::vector<std::string>& cors_exposed_header_names) {
-  if (kCorsSafelistedResponseHeaderNames.contains(base::ToLowerASCII(name))) {
+  if (network::cors::IsCorsSafelistedResponseHeaderName(name)) {
+    return true;
+  }
+  // "content-range" is not a standard CORS-safelisted response header, but it
+  // is required by C++ media loaders (e.g. WebMediaPlayer) to process "206
+  // Partial Content" range responses. We permit it in URLResponseHead to avoid
+  // breaking media playback, while it remains filtered out and hidden from
+  // JavaScript's view in the renderer.
+  if (base::ToLowerASCII(name) == "content-range") {
     return true;
   }
   for (const auto& exposed : cors_exposed_header_names) {
diff --git a/third_party/blink/renderer/platform/loader/cors/cors.cc b/third_party/blink/renderer/platform/loader/cors/cors.cc
index 107209d2..60e2ae1 100644
--- a/third_party/blink/renderer/platform/loader/cors/cors.cc
+++ b/third_party/blink/renderer/platform/loader/cors/cors.cc
@@ -205,22 +205,7 @@
 }
 
 bool IsCorsSafelistedResponseHeader(const String& name) {
-  // LINT.IfChange(allowed_cross_origin_response_headers)
-  // https://fetch.spec.whatwg.org/#cors-safelisted-response-header-name
-  // TODO(dcheng): Consider using a flat_set here with a transparent comparator.
-  DEFINE_THREAD_SAFE_STATIC_LOCAL(HTTPHeaderSet,
-                                  allowed_cross_origin_response_headers,
-                                  ({
-                                      "cache-control",
-                                      "content-language",
-                                      "content-length",
-                                      "content-type",
-                                      "expires",
-                                      "last-modified",
-                                      "pragma",
-                                  }));
-  // LINT.ThenChange(third_party/blink/common/service_worker/service_worker_loader_helpers.cc:kCorsSafelistedResponseHeaderNames)
-  return allowed_cross_origin_response_headers.contains(name.Ascii());
+  return network::cors::IsCorsSafelistedResponseHeaderName(name.Latin1());
 }
 
 // In the spec, https://fetch.spec.whatwg.org/#ref-for-concept-request-mode,
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
index 5b56353d..c3e4b58 100755
--- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
+++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -547,8 +547,8 @@
         ],
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/services/network/public/cpp/cors/cors_unittest.cc b/services/network/public/cpp/cors/cors_unittest.cc
index 991dfd7..590471ee1 100644
--- a/services/network/public/cpp/cors/cors_unittest.cc
+++ b/services/network/public/cpp/cors/cors_unittest.cc
@@ -218,6 +218,33 @@
   EXPECT_FALSE(IsCorsSafelistedHeader("user-agent", "foo"));
 }
 
+TEST_F(CorsTest, SafelistedResponseHeaderName) {
+  // The seven CORS-safelisted response header names, in mixed case to exercise
+  // the case-insensitive match.
+  static constexpr std::string_view kSafelisted[] = {
+      "cache-control", "Content-Language", "CONTENT-LENGTH", "content-type",
+      "Expires",       "Last-Modified",    "pragma",
+  };
+  for (std::string_view name : kSafelisted) {
+    SCOPED_TRACE(name);
+    EXPECT_TRUE(IsCorsSafelistedResponseHeaderName(name));
+  }
+
+  // "content-range" is deliberately excluded: it is a media-only carve-out
+  // kept out of the JS-visible safelist. The rest are ordinary non-safelisted
+  // headers.
+  static constexpr std::string_view kNotSafelisted[] = {
+      "content-range",
+      "set-cookie",
+      "x-auth-token",
+      "sec-ch-ua",
+  };
+  for (std::string_view name : kNotSafelisted) {
+    SCOPED_TRACE(name);
+    EXPECT_FALSE(IsCorsSafelistedResponseHeaderName(name));
+  }
+}
+
 TEST_F(CorsTest, SafelistedAccept) {
   EXPECT_TRUE(IsCorsSafelistedHeader("accept", "text/html"));
   EXPECT_TRUE(IsCorsSafelistedHeader("AccepT", "text/html"));
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.