Low chrome Logic Error 🔧 Commit mapped

Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactPolicy bypass in Enterprise
DescriptionPolicy bypass in Enterprise
ComponentEnterprise
Bug ClassLogic Error
Tracker513612928
Fix commit4a017a0d4374 (chromium/src) +61/-2
CISA KEVNot listed
CreditedGoogle
Disclosed2026-07-29

Changed Functions

FunctionChangeNotes
if
components/url_matcher/url_matcher.cc
modified

Files Changed

  • components/url_matcher/url_matcher.cc
  • components/url_matcher/url_matcher_unittest.cc
From 4a017a0d4374a27fa572b65df2be471bda4421a0 Mon Sep 17 00:00:00 2001
From: Dominic Battre <[email protected]>
Date: Wed, 03 Jun 2026 00:38:00 -0700
Subject: [PATCH] Collapse trailing dots in URLMatcher host suffix canonicalization

This change modifies
`URLMatcherConditionFactory::CanonicalizeHostSuffix` to strip all
trailing dots from the suffix and append exactly one dot.

This collapses suffixes like "host", "host.", and "host.." to the same
canonical "host.". This prevents FQDNs with multiple trailing dots from
bypassing host-suffix filters, as GURL accepts hosts with empty labels
(e.g., trailing dots) and can present them with multiple dots, whereas
the filter side might only store one.

Also added unit tests in `url_matcher_unittest.cc` to verify the fix
with various combinations of trailing dots on both the URL host and the
matching patterns.

Fixed: 513612928
Change-Id: I4ef10d3b1a85fc016458ba1aac417af16a6a6964
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7894782
Reviewed-by: Steinar H Gunderson <[email protected]>
Auto-Submit: Dominic Battré <[email protected]>
Commit-Queue: Steinar H Gunderson <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1640754}
---

diff --git a/components/url_matcher/url_matcher.cc b/components/url_matcher/url_matcher.cc
index bb45ca1..20b33f3 100644
--- a/components/url_matcher/url_matcher.cc
+++ b/components/url_matcher/url_matcher.cc
@@ -526,10 +526,17 @@
 
 std::string URLMatcherConditionFactory::CanonicalizeHostSuffix(
     const std::string& suffix) const {
-  if (suffix.empty()) {
+  // Strip all trailing dots, then append exactly one. This collapses
+  // "host", "host." and "host.." (etc.) to the same canonical "host." so
+  // that multi-dot FQDN forms cannot bypass host-suffix filters. GURL
+  // accepts hosts with empty labels (see url/url_idna_icu.cc), so the
+  // URL side can otherwise present "host.." while the filter side stores
+  // "host.".
+  const size_t end = suffix.find_last_not_of('.');
+  if (end == std::string::npos) {
     return ".";
   }
-  return suffix.back() == '.' ? suffix : suffix + ".";
+  return suffix.substr(0, end + 1) + ".";
 }
 
 std::string URLMatcherConditionFactory::CanonicalizeHostPrefix(
diff --git a/components/url_matcher/url_matcher_unittest.cc b/components/url_matcher/url_matcher_unittest.cc
index 42020eb..1a84895d 100644
--- a/components/url_matcher/url_matcher_unittest.cc
+++ b/components/url_matcher/url_matcher_unittest.cc
@@ -320,6 +320,11 @@
       "&ie=UTF-8&ion=1#hl=en&output=search&sclient=psy-ab"
       "&q=chrome%20is%20awesome");
   std::string url2 = factory.CanonicalizeURLForComponentSearches(gurl2);
+  GURL gurl3(
+      "https://www.google.com..:1234/webhp?sourceid=chrome-instant"
+      "&ie=UTF-8&ion=1#hl=en&output=search&sclient=psy-ab"
+      "&q=chrome%20is%20awesome");
+  std::string url3 = factory.CanonicalizeURLForComponentSearches(gurl3);
 
   // Test host component.
   EXPECT_TRUE(Matches(factory.CreateHostPrefixCondition(std::string()), url));
@@ -335,34 +340,81 @@
 
   EXPECT_TRUE(Matches(factory.CreateHostSuffixCondition(std::string()), url));
   EXPECT_TRUE(Matches(factory.CreateHostSuffixCondition(std::string()), url2));
+  EXPECT_TRUE(Matches(factory.CreateHostSuffixCondition(std::string()), url3));
   EXPECT_TRUE(Matches(factory.CreateHostSuffixCondition("com"), url));
   EXPECT_TRUE(Matches(factory.CreateHostSuffixCondition("com"), url2));
+  EXPECT_TRUE(Matches(factory.CreateHostSuffixCondition("com"), url3));
   EXPECT_TRUE(Matches(factory.CreateHostSuffixCondition(".com"), url));
+  EXPECT_TRUE(Matches(factory.CreateHostSuffixCondition(".com"), url3));
   EXPECT_TRUE(
       Matches(factory.CreateHostSuffixCondition("www.google.com"), url));
   EXPECT_TRUE(
+      Matches(factory.CreateHostSuffixCondition("www.google.com"), url3));
+  EXPECT_TRUE(
       Matches(factory.CreateHostSuffixCondition(".www.google.com"), url));
   EXPECT_TRUE(
       Matches(factory.CreateHostSuffixCondition(".www.google.com"), url2));
   EXPECT_TRUE(
+      Matches(factory.CreateHostSuffixCondition(".www.google.com"), url3));
+  EXPECT_TRUE(
       Matches(factory.CreateHostSuffixCondition(".www.google.com."), url));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostSuffixCondition(".www.google.com."), url3));
+
+  // Suffix patterns with multiple trailing dots should be canonicalized to a
+  // single trailing dot and match.
+  EXPECT_TRUE(
+      Matches(factory.CreateHostSuffixCondition("www.google.com.."), url));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostSuffixCondition("www.google.com.."), url2));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostSuffixCondition("www.google.com.."), url3));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostSuffixCondition(".www.google.com.."), url));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostSuffixCondition(".www.google.com.."), url2));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostSuffixCondition(".www.google.com.."), url3));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostSuffixCondition(".www.google.com..."), url));
+
   EXPECT_FALSE(Matches(factory.CreateHostSuffixCondition("www"), url));
   EXPECT_FALSE(
       Matches(factory.CreateHostSuffixCondition("www.google.com/"), url));
   EXPECT_FALSE(Matches(factory.CreateHostSuffixCondition("webhp"), url));
 
   EXPECT_FALSE(Matches(factory.CreateHostEqualsCondition(std::string()), url));
+  EXPECT_FALSE(Matches(factory.CreateHostEqualsCondition(std::string()), url3));
   EXPECT_FALSE(Matches(factory.CreateHostEqualsCondition("www"), url));
   EXPECT_TRUE(
       Matches(factory.CreateHostEqualsCondition("www.google.com"), url));
   EXPECT_TRUE(
       Matches(factory.CreateHostEqualsCondition("www.google.com"), url2));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostEqualsCondition("www.google.com"), url3));
   EXPECT_FALSE(
       Matches(factory.CreateHostEqualsCondition("www.google.com/"), url));
   EXPECT_TRUE(
       Matches(factory.CreateHostEqualsCondition(".www.google.com."), url));
   EXPECT_TRUE(
       Matches(factory.CreateHostEqualsCondition(".www.google.com."), url2));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostEqualsCondition(".www.google.com."), url3));
+
+  // Equals patterns with multiple trailing dots should be canonicalized to a
+  // single trailing dot and match.
+  EXPECT_TRUE(
+      Matches(factory.CreateHostEqualsCondition("www.google.com.."), url));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostEqualsCondition("www.google.com.."), url2));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostEqualsCondition("www.google.com.."), url3));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostEqualsCondition(".www.google.com.."), url));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostEqualsCondition(".www.google.com.."), url2));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostEqualsCondition(".www.google.com.."), url3));
 
   // Test path component.
   EXPECT_TRUE(Matches(factory.CreatePathPrefixCondition(std::string()), url));
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/components/url_matcher/url_matcher_unittest.cc b/components/url_matcher/url_matcher_unittest.cc
index 42020eb..1a84895d 100644
--- a/components/url_matcher/url_matcher_unittest.cc
+++ b/components/url_matcher/url_matcher_unittest.cc
@@ -320,6 +320,11 @@
       "&ie=UTF-8&ion=1#hl=en&output=search&sclient=psy-ab"
       "&q=chrome%20is%20awesome");
   std::string url2 = factory.CanonicalizeURLForComponentSearches(gurl2);
+  GURL gurl3(
+      "https://www.google.com..:1234/webhp?sourceid=chrome-instant"
+      "&ie=UTF-8&ion=1#hl=en&output=search&sclient=psy-ab"
+      "&q=chrome%20is%20awesome");
+  std::string url3 = factory.CanonicalizeURLForComponentSearches(gurl3);
 
   // Test host component.
   EXPECT_TRUE(Matches(factory.CreateHostPrefixCondition(std::string()), url));
@@ -335,34 +340,81 @@
 
   EXPECT_TRUE(Matches(factory.CreateHostSuffixCondition(std::string()), url));
   EXPECT_TRUE(Matches(factory.CreateHostSuffixCondition(std::string()), url2));
+  EXPECT_TRUE(Matches(factory.CreateHostSuffixCondition(std::string()), url3));
   EXPECT_TRUE(Matches(factory.CreateHostSuffixCondition("com"), url));
   EXPECT_TRUE(Matches(factory.CreateHostSuffixCondition("com"), url2));
+  EXPECT_TRUE(Matches(factory.CreateHostSuffixCondition("com"), url3));
   EXPECT_TRUE(Matches(factory.CreateHostSuffixCondition(".com"), url));
+  EXPECT_TRUE(Matches(factory.CreateHostSuffixCondition(".com"), url3));
   EXPECT_TRUE(
       Matches(factory.CreateHostSuffixCondition("www.google.com"), url));
   EXPECT_TRUE(
+      Matches(factory.CreateHostSuffixCondition("www.google.com"), url3));
+  EXPECT_TRUE(
       Matches(factory.CreateHostSuffixCondition(".www.google.com"), url));
   EXPECT_TRUE(
       Matches(factory.CreateHostSuffixCondition(".www.google.com"), url2));
   EXPECT_TRUE(
+      Matches(factory.CreateHostSuffixCondition(".www.google.com"), url3));
+  EXPECT_TRUE(
       Matches(factory.CreateHostSuffixCondition(".www.google.com."), url));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostSuffixCondition(".www.google.com."), url3));
+
+  // Suffix patterns with multiple trailing dots should be canonicalized to a
+  // single trailing dot and match.
+  EXPECT_TRUE(
+      Matches(factory.CreateHostSuffixCondition("www.google.com.."), url));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostSuffixCondition("www.google.com.."), url2));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostSuffixCondition("www.google.com.."), url3));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostSuffixCondition(".www.google.com.."), url));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostSuffixCondition(".www.google.com.."), url2));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostSuffixCondition(".www.google.com.."), url3));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostSuffixCondition(".www.google.com..."), url));
+
   EXPECT_FALSE(Matches(factory.CreateHostSuffixCondition("www"), url));
   EXPECT_FALSE(
       Matches(factory.CreateHostSuffixCondition("www.google.com/"), url));
   EXPECT_FALSE(Matches(factory.CreateHostSuffixCondition("webhp"), url));
 
   EXPECT_FALSE(Matches(factory.CreateHostEqualsCondition(std::string()), url));
+  EXPECT_FALSE(Matches(factory.CreateHostEqualsCondition(std::string()), url3));
   EXPECT_FALSE(Matches(factory.CreateHostEqualsCondition("www"), url));
   EXPECT_TRUE(
       Matches(factory.CreateHostEqualsCondition("www.google.com"), url));
   EXPECT_TRUE(
       Matches(factory.CreateHostEqualsCondition("www.google.com"), url2));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostEqualsCondition("www.google.com"), url3));
   EXPECT_FALSE(
       Matches(factory.CreateHostEqualsCondition("www.google.com/"), url));
   EXPECT_TRUE(
       Matches(factory.CreateHostEqualsCondition(".www.google.com."), url));
   EXPECT_TRUE(
       Matches(factory.CreateHostEqualsCondition(".www.google.com."), url2));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostEqualsCondition(".www.google.com."), url3));
+
+  // Equals patterns with multiple trailing dots should be canonicalized to a
+  // single trailing dot and match.
+  EXPECT_TRUE(
+      Matches(factory.CreateHostEqualsCondition("www.google.com.."), url));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostEqualsCondition("www.google.com.."), url2));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostEqualsCondition("www.google.com.."), url3));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostEqualsCondition(".www.google.com.."), url));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostEqualsCondition(".www.google.com.."), url2));
+  EXPECT_TRUE(
+      Matches(factory.CreateHostEqualsCondition(".www.google.com.."), url3));
 
   // Test path component.
   EXPECT_TRUE(Matches(factory.CreatePathPrefixCondition(std::string()), url));
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.