Low chrome Logic Error 🔧 Commit mapped

Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactImproper input validation in Cookies
DescriptionImproper input validation in Cookies
ComponentCookies
Bug ClassLogic Error
Tracker533511967
Fix commitbbf5240096c5 (chromium/src) +362/-26
CISA KEVNot listed
CreditedGoogle
Disclosed2026-08-25

Changed Functions

FunctionChangeNotes
TEST
net/cookies/canonical_cookie_unittest.cc
modified
for
net/cookies/canonical_cookie_unittest.cc
modified

Files Changed

  • net/cookies/canonical_cookie.cc
  • net/cookies/canonical_cookie.h
  • net/cookies/canonical_cookie_unittest.cc
From bbf5240096c5e533b0c62ce3cc6979caf48f7bdb Mon Sep 17 00:00:00 2001
From: Etienne Bergeron <etienneb@google.com>
Date: Thu, 23 Jul 2026 08:20:41 -0700
Subject: [PATCH] [net/cookies] Reject ambiguous nameless cookies during sanitized creation

RFC 6265bis §11.17 mandates that nameless cookies should not contain
restricted prefixes (like __Host- or __Secure-) in their values, to
prevent subdomain cookie injection to naive backend parsers.

While standard parsing in CanonicalCookie::Create() blocks nameless
cookies containing '=' via the EXCLUDE_AMBIGUOUS_SERIALIZATION check
(gated on the kCookieParseRejectEmptyNameAmbiguous feature), the
Mojo-facing creation path in CanonicalCookie::CreateSanitizedCookie()
and the validator CanonicalCookie::IsCanonicalForFromStorage() lacked
this validation step.

This CL replicates the EXCLUDE_AMBIGUOUS_SERIALIZATION check inside
CreateSanitizedCookie() and IsCanonicalForFromStorage() to ensure
nameless cookies containing '=' in their values are correctly blocked
across all creation surfaces.

Bug: 533511967
Test: net_unittests --gtest_filter=CanonicalCookieTest.*
Test: services_unittests --gtest_filter=*RestrictedCookieManagerTest.*
Change-Id: I9545da06ab68422e1d65226e4d2794ee98a98458
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8088135
Reviewed-by: Adam Rice <ricea@chromium.org>
Commit-Queue: Etienne Bergeron <etienneb@chromium.org>
Reviewed-by: Nidhi Jaju <nidhijaju@chromium.org>
Reviewed-by: Maks Orlovich <morlovich@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1667115}
---

diff --git a/net/cookies/canonical_cookie.cc b/net/cookies/canonical_cookie.cc
index d8bc1573..6d4f43c 100644
--- a/net/cookies/canonical_cookie.cc
+++ b/net/cookies/canonical_cookie.cc
@@ -703,6 +703,14 @@
         net::CookieInclusionStatus::ExclusionReason::EXCLUDE_INVALID_PREFIX);
   }
 
+  if (name.empty() &&
+      base::FeatureList::IsEnabled(
+          features::kCookieParseRejectEmptyNameAmbiguous) &&
+      value.contains('=')) {
+    status->AddExclusionReason(CookieInclusionStatus::ExclusionReason::
+                                   EXCLUDE_AMBIGUOUS_SERIALIZATION);
+  }
+
   if (!cookie_util::IsCookiePartitionedValid(url, secure, partition_key)) {
     status->AddExclusionReason(net::CookieInclusionStatus::ExclusionReason::
                                    EXCLUDE_INVALID_PARTITIONED);
@@ -1076,6 +1084,13 @@
     return Fail(CanonicalizationFailure::kEmptyNameWithHiddenPrefix);
   }
 
+  if (Name().empty() &&
+      base::FeatureList::IsEnabled(
+          features::kCookieParseRejectEmptyNameAmbiguous) &&
+      Value().contains('=')) {
+    return Fail(CanonicalizationFailure::kEmptyNameWithAmbiguousValue);
+  }
+
   if (IsPartitioned() && !CookiePartitionKey::HasNonce(PartitionKey()) &&
       !SecureAttribute()) {
     return Fail(CanonicalizationFailure::kPartitionedInsecure);
@@ -1253,6 +1268,9 @@
         return "kEmptyNameWithHiddenPrefix";
       case CanonicalCookie::CanonicalizationFailure::kPartitionedInsecure:
         return "kPartitionedInsecure";
+      case CanonicalCookie::CanonicalizationFailure::
+          kEmptyNameWithAmbiguousValue:
+        return "kEmptyNameWithAmbiguousValue";
     }
     NOTREACHED();
   }();
diff --git a/net/cookies/canonical_cookie.h b/net/cookies/canonical_cookie.h
index b7dff30..b61a2cfc 100644
--- a/net/cookies/canonical_cookie.h
+++ b/net/cookies/canonical_cookie.h
@@ -83,6 +83,7 @@
     kInvalidHostHttpPrefix,
     kEmptyNameWithHiddenPrefix,
     kPartitionedInsecure,
+    kEmptyNameWithAmbiguousValue,
   };
 
   // Carries metadata related to the canonicalization results for a given
diff --git a/net/cookies/canonical_cookie_unittest.cc b/net/cookies/canonical_cookie_unittest.cc
index fa69297..65a5bd1 100644
--- a/net/cookies/canonical_cookie_unittest.cc
+++ b/net/cookies/canonical_cookie_unittest.cc
@@ -579,6 +579,76 @@
   }
 }
 
+TEST(CanonicalCookieTest, CreateSanitizedCookieRejectEmptyNameAmbiguous) {
+  CookieInclusionStatus status;
+  std::unique_ptr<CanonicalCookie> cc;
+  GURL url("https://www.example.com");
+  base::Time now = base::Time::Now();
+
+  constexpr std::string_view kAmbiguousValues[] = {
+      "=__Host-session=evil",
+      "foo=bar",
+      "session=123",
+      "a=",
+  };
+
+  // With the feature explicitly enabled, setting a nameless cookie with an
+  // ambiguous value (contains '=') should fail for CreateSanitizedCookie and
+  // FromStorage.
+  {
+    base::test::ScopedFeatureList features;
+    features.InitAndEnableFeature(
+        features::kCookieParseRejectEmptyNameAmbiguous);
+
+    for (std::string_view ambiguous_value : kAmbiguousValues) {
+      status = CookieInclusionStatus();
+      cc = CanonicalCookie::CreateSanitizedCookie(
+          url, "", ambiguous_value.data(), "", "/", base::Time(), base::Time(),
+          base::Time(), /*secure=*/true, /*http_only=*/false,
+          CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT,
+          /*partition_key=*/std::nullopt, &status);
+      EXPECT_FALSE(cc);
+      EXPECT_TRUE(
+          status.HasExclusionReason(CookieInclusionStatus::ExclusionReason::
+                                        EXCLUDE_AMBIGUOUS_SERIALIZATION));
+
+      cc = CanonicalCookie::FromStorage(
+          "", ambiguous_value.data(), "example.com", "/", now,
+          now + base::Hours(1), now, now, /*secure=*/true, /*httponly=*/false,
+          CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT,
+          /*partition_key=*/std::nullopt, CookieSourceScheme::kSecure, 443,
+          CookieSourceType::kOther, CanonicalCookieFromStorageCallSite::kTests);
+      EXPECT_FALSE(cc);
+    }
+  }
+
+  // Now run both with the feature disabled.
+  {
+    base::test::ScopedFeatureList features;
+    features.InitAndDisableFeature(
+        features::kCookieParseRejectEmptyNameAmbiguous);
+
+    for (std::string_view ambiguous_value : kAmbiguousValues) {
+      status = CookieInclusionStatus();
+      cc = CanonicalCookie::CreateSanitizedCookie(
+          url, "", ambiguous_value.data(), "", "/", base::Time(), base::Time(),
+          base::Time(), /*secure=*/true, /*http_only=*/false,
+          CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT,
+          /*partition_key=*/std::nullopt, &status);
+      EXPECT_TRUE(cc);
+      EXPECT_TRUE(status.IsInclude());
+
+      cc = CanonicalCookie::FromStorage(
+          "", ambiguous_value.data(), "example.com", "/", now,
+          now + base::Hours(1), now, now, /*secure=*/true, /*httponly=*/false,
+          CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT,
+          /*partition_key=*/std::nullopt, CookieSourceScheme::kSecure, 443,
+          CookieSourceType::kOther, CanonicalCookieFromStorageCallSite::kTests);
+      EXPECT_TRUE(cc);
+    }
+  }
+}
+
 // Test that a cookie string with an empty domain attribute generates a
 // canonical host cookie.
 TEST(CanonicalCookieTest, CreateHostCookieFromString) {
@@ -4507,10 +4577,18 @@
       std::string(), base::Time(), base::Time(), base::Time(), false /*secure*/,
       false /*httponly*/, CookieSameSite::NO_RESTRICTION,
       COOKIE_PRIORITY_DEFAULT, std::nullopt /*partition_key*/, &status);
-  EXPECT_TRUE(cc);
-  std::vector<std::unique_ptr<CanonicalCookie>> cookies;
-  cookies.push_back(std::move(cc));
-  MatchCookieLineToVector("ambiguous=value", cookies);
+  if (base::FeatureList::IsEnabled(
+          features::kCookieParseRejectEmptyNameAmbiguous)) {
+    EXPECT_FALSE(cc);
+    EXPECT_TRUE(
+        status.HasExclusionReason(CookieInclusionStatus::ExclusionReason::
+                                      EXCLUDE_AMBIGUOUS_SERIALIZATION));
+  } else {
+    EXPECT_TRUE(cc);
+    std::vector<std::unique_ptr<CanonicalCookie>> cookies;
+    cookies.push_back(std::move(cc));
+    MatchCookieLineToVector("ambiguous=value", cookies);
+  }
 
   // Check that name can't contain an equal sign ("ambiguous=name=value" should
   // correctly be parsed as name: "ambiguous" and value "name=value", so
@@ -4638,8 +4716,16 @@
       one_hour_from_now, one_hour_ago, true, false,
       CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT,
       std::nullopt /*partition_key*/, &status));
-  EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
-      {CookieInclusionStatus::ExclusionReason::EXCLUDE_INVALID_PREFIX}));
+  if (base::FeatureList::IsEnabled(
+          features::kCookieParseRejectEmptyNameAmbiguous)) {
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/net/cookies/canonical_cookie_unittest.cc b/net/cookies/canonical_cookie_unittest.cc
index fa69297..65a5bd1 100644
--- a/net/cookies/canonical_cookie_unittest.cc
+++ b/net/cookies/canonical_cookie_unittest.cc
@@ -579,6 +579,76 @@
   }
 }
 
+TEST(CanonicalCookieTest, CreateSanitizedCookieRejectEmptyNameAmbiguous) {
+  CookieInclusionStatus status;
+  std::unique_ptr<CanonicalCookie> cc;
+  GURL url("https://www.example.com");
+  base::Time now = base::Time::Now();
+
+  constexpr std::string_view kAmbiguousValues[] = {
+      "=__Host-session=evil",
+      "foo=bar",
+      "session=123",
+      "a=",
+  };
+
+  // With the feature explicitly enabled, setting a nameless cookie with an
+  // ambiguous value (contains '=') should fail for CreateSanitizedCookie and
+  // FromStorage.
+  {
+    base::test::ScopedFeatureList features;
+    features.InitAndEnableFeature(
+        features::kCookieParseRejectEmptyNameAmbiguous);
+
+    for (std::string_view ambiguous_value : kAmbiguousValues) {
+      status = CookieInclusionStatus();
+      cc = CanonicalCookie::CreateSanitizedCookie(
+          url, "", ambiguous_value.data(), "", "/", base::Time(), base::Time(),
+          base::Time(), /*secure=*/true, /*http_only=*/false,
+          CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT,
+          /*partition_key=*/std::nullopt, &status);
+      EXPECT_FALSE(cc);
+      EXPECT_TRUE(
+          status.HasExclusionReason(CookieInclusionStatus::ExclusionReason::
+                                        EXCLUDE_AMBIGUOUS_SERIALIZATION));
+
+      cc = CanonicalCookie::FromStorage(
+          "", ambiguous_value.data(), "example.com", "/", now,
+          now + base::Hours(1), now, now, /*secure=*/true, /*httponly=*/false,
+          CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT,
+          /*partition_key=*/std::nullopt, CookieSourceScheme::kSecure, 443,
+          CookieSourceType::kOther, CanonicalCookieFromStorageCallSite::kTests);
+      EXPECT_FALSE(cc);
+    }
+  }
+
+  // Now run both with the feature disabled.
+  {
+    base::test::ScopedFeatureList features;
+    features.InitAndDisableFeature(
+        features::kCookieParseRejectEmptyNameAmbiguous);
+
+    for (std::string_view ambiguous_value : kAmbiguousValues) {
+      status = CookieInclusionStatus();
+      cc = CanonicalCookie::CreateSanitizedCookie(
+          url, "", ambiguous_value.data(), "", "/", base::Time(), base::Time(),
+          base::Time(), /*secure=*/true, /*http_only=*/false,
+          CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT,
+          /*partition_key=*/std::nullopt, &status);
+      EXPECT_TRUE(cc);
+      EXPECT_TRUE(status.IsInclude());
+
+      cc = CanonicalCookie::FromStorage(
+          "", ambiguous_value.data(), "example.com", "/", now,
+          now + base::Hours(1), now, now, /*secure=*/true, /*httponly=*/false,
+          CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT,
+          /*partition_key=*/std::nullopt, CookieSourceScheme::kSecure, 443,
+          CookieSourceType::kOther, CanonicalCookieFromStorageCallSite::kTests);
+      EXPECT_TRUE(cc);
+    }
+  }
+}
+
 // Test that a cookie string with an empty domain attribute generates a
 // canonical host cookie.
 TEST(CanonicalCookieTest, CreateHostCookieFromString) {
@@ -4507,10 +4577,18 @@
       std::string(), base::Time(), base::Time(), base::Time(), false /*secure*/,
       false /*httponly*/, CookieSameSite::NO_RESTRICTION,
       COOKIE_PRIORITY_DEFAULT, std::nullopt /*partition_key*/, &status);
-  EXPECT_TRUE(cc);
-  std::vector<std::unique_ptr<CanonicalCookie>> cookies;
-  cookies.push_back(std::move(cc));
-  MatchCookieLineToVector("ambiguous=value", cookies);
+  if (base::FeatureList::IsEnabled(
+          features::kCookieParseRejectEmptyNameAmbiguous)) {
+    EXPECT_FALSE(cc);
+    EXPECT_TRUE(
+        status.HasExclusionReason(CookieInclusionStatus::ExclusionReason::
+                                      EXCLUDE_AMBIGUOUS_SERIALIZATION));
+  } else {
+    EXPECT_TRUE(cc);
+    std::vector<std::unique_ptr<CanonicalCookie>> cookies;
+    cookies.push_back(std::move(cc));
+    MatchCookieLineToVector("ambiguous=value", cookies);
+  }
 
   // Check that name can't contain an equal sign ("ambiguous=name=value" should
   // correctly be parsed as name: "ambiguous" and value "name=value", so
@@ -4638,8 +4716,16 @@
       one_hour_from_now, one_hour_ago, true, false,
       CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT,
       std::nullopt /*partition_key*/, &status));
-  EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
-      {CookieInclusionStatus::ExclusionReason::EXCLUDE_INVALID_PREFIX}));
+  if (base::FeatureList::IsEnabled(
+          features::kCookieParseRejectEmptyNameAmbiguous)) {
+    EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
+        {CookieInclusionStatus::ExclusionReason::EXCLUDE_INVALID_PREFIX,
+         CookieInclusionStatus::ExclusionReason::
+             EXCLUDE_AMBIGUOUS_SERIALIZATION}));
+  } else {
+    EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
+        {CookieInclusionStatus::ExclusionReason::EXCLUDE_INVALID_PREFIX}));
+  }
 
   EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
       GURL("https://www.foo.com"), "", "__Host-A", "", "/", two_hours_ago,
@@ -4654,8 +4740,16 @@
       one_hour_from_now, one_hour_ago, true, false,
       CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT,
       std::nullopt /*partition_key*/, &status));
-  EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
-      {CookieInclusionStatus::ExclusionReason::EXCLUDE_INVALID_PREFIX}));
+  if (base::FeatureList::IsEnabled(
+          features::kCookieParseRejectEmptyNameAmbiguous)) {
+    EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
+        {CookieInclusionStatus::ExclusionReason::EXCLUDE_INVALID_PREFIX,
+         CookieInclusionStatus::ExclusionReason::
+             EXCLUDE_AMBIGUOUS_SERIALIZATION}));
+  } else {
+    EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
+        {CookieInclusionStatus::ExclusionReason::EXCLUDE_INVALID_PREFIX}));
+  }
 
   EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
       GURL("https://www.foo.com"), "", "__Secure-A", "", "/", two_hours_ago,
diff --git a/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc b/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc
index fc1aa432..9c6aa55 100644
--- a/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc
+++ b/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc
@@ -812,9 +812,8 @@
                       {"google.izzle", "A=", "B", "/path"},
                       {"google.izzle", "C ", "D", "/path"},
 
-                      // A canonical cookie for same eTLD+1. This one will get
-                      // dropped out of precaution to avoid confusing the site,
-                      // even though there is nothing wrong with it.
+                      // A canonical cookie for same eTLD+1. This one will be
+                      // preserved while non-canonical cookies are purged.
                       {"sub.google.izzle", "E", "F", "/path"},
 
                       // A canonical cookie for another eTLD+1
@@ -841,19 +840,36 @@
   stmt.Clear();
   db.reset();
 
-  // Reopen the store and confirm that the only cookie loaded is the
-  // canonical one on an unrelated domain.
+  // Reopen the store and confirm that valid cookies (including sibling domain
+  // sub.google.izzle) are preserved while only the invalid non-canonical
+  // cookies are purged.
   CanonicalCookieVector cookies = CreateAndLoad(
       /*crypt_cookies=*/false, /*restore_old_session_cookies=*/false);
-  ASSERT_EQ(1U, cookies.size());
-  EXPECT_STREQ("chromium.org", cookies[0]->Domain().c_str());
-  EXPECT_STREQ("G", cookies[0]->Name().c_str());
-  EXPECT_STREQ("H", cookies[0]->Value().c_str());
-  EXPECT_STREQ("/dir", cookies[0]->Path().c_str());
-  EXPECT_EQ(last_update, cookies[0]->LastUpdateDate());
+  ASSERT_EQ(2U, cookies.size());
+
+  // Find sub.google.izzle and chromium.org cookies.
+  const CanonicalCookie* sub_cookie = nullptr;
+  const CanonicalCookie* chrom_cookie = nullptr;
+  for (const auto& cookie : cookies) {
+    if (cookie->Domain() == "sub.google.izzle") {
+      sub_cookie = cookie.get();
+    } else if (cookie->Domain() == "chromium.org") {
+      chrom_cookie = cookie.get();
+    }
+  }
+  ASSERT_TRUE(sub_cookie);
+  ASSERT_TRUE(chrom_cookie);
+
+  EXPECT_STREQ("sub.google.izzle", sub_cookie->Domain().c_str());
+  EXPECT_STREQ("E", sub_cookie->Name().c_str());
+  EXPECT_STREQ("F", sub_cookie->Value().c_str());
+
+  EXPECT_STREQ("chromium.org", chrom_cookie->Domain().c_str());
+  EXPECT_STREQ("G", chrom_cookie->Name().c_str());
+  EXPECT_STREQ("H", chrom_cookie->Value().c_str());
   DestroyStore();
 
-  // Make sure that we only have one row left.
+  // Make sure that we only have two rows left in the database.
   db = std::make_unique<sql::Database>(sql::test::kTestTag);
   ASSERT_TRUE(db->Open(store_name));
   sql::Statement verify_stmt(db->GetUniqueStatement("SELECT * FROM COOKIES"));
@@ -861,7 +877,83 @@
 
   EXPECT_TRUE(verify_stmt.Step());
   EXPECT_TRUE(verify_stmt.Succeeded());
-  // Confirm only one match.
+  EXPECT_TRUE(verify_stmt.Step());
+  EXPECT_TRUE(verify_stmt.Succeeded());
+  // Confirm only two matches.
+  EXPECT_FALSE(verify_stmt.Step());
+}
+
+TEST_F(SQLitePersistentCookieStoreTest,
+       TestAmbiguousNamelessCookieSingleDeletion) {
+  base::test::ScopedFeatureList features;
+  features.InitAndEnableFeature(
+      net::features::kCookieParseRejectEmptyNameAmbiguous);
+
+  CreateAndLoad(/*crypt_cookies=*/false, /*restore_old_session_cookies=*/false);
+  DestroyStore();
+
+  // Insert a valid cookie and a pre-existing ambiguous nameless cookie for
+  // example.com.
+  base::FilePath store_name(temp_dir_.GetPath().Append(kCookieFilename));
+  std::unique_ptr<sql::Database> db(
+      std::make_unique<sql::Database>(sql::test::kTestTag));
+  ASSERT_TRUE(db->Open(store_name));
+  sql::Statement stmt(db->GetUniqueStatement(
+      "INSERT INTO cookies (creation_utc, host_key, top_frame_site_key, name, "
+      "value, encrypted_value, path, expires_utc, is_secure, is_httponly, "
+      "samesite, last_access_utc, has_expires, is_persistent, priority, "
+      "source_scheme, source_port, last_update_utc, source_type, "
+      "has_cross_site_ancestor) "
+      "VALUES (?,?,?,?,?,'',?,0,0,0,0,0,1,1,0,?,?,?,0,0)"));
+  ASSERT_TRUE(stmt.is_valid());
+
+  struct CookieInfo {
+    const char* domain;
+    const char* name;
+    const char* value;
+    const char* path;
+  } cookies_info[] = {
+      {"example.com", "", "=__Host-session=evil", "/"},
+      {"example.com", "sid", "123", "/"},
+  };
+
+  int64_t creation_time = 1;
+  base::Time last_update(base::Time::Now());
+  for (auto& cookie_info : cookies_info) {
+    stmt.Reset(true);
+    stmt.BindInt64(0, creation_time++);
+    stmt.BindString(1, cookie_info.domain);
+    stmt.BindString(2, net::kEmptyCookiePartitionKey);
+    stmt.BindString(3, cookie_info.name);
+    stmt.BindString(4, cookie_info.value);
+    stmt.BindString(5, cookie_info.path);
+    stmt.BindInt(6, static_cast<int>(CookieSourceScheme::kUnset));
+    stmt.BindInt(7, SQLitePersistentCookieStore::kDefaultUnknownPort);
+    stmt.BindTime(8, last_update);
+    ASSERT_TRUE(stmt.Run());
+  }
+  stmt.Clear();
+  db.reset();
+
+  // Load store and verify that only the valid "sid" cookie is returned, while
+  // the ambiguous nameless cookie is discarded without dropping valid sibling
+  // cookies.
+  CanonicalCookieVector cookies = CreateAndLoad(
+      /*crypt_cookies=*/false, /*restore_old_session_cookies=*/false);
+  ASSERT_EQ(1U, cookies.size());
+  EXPECT_EQ("sid", cookies[0]->Name());
+  EXPECT_EQ("123", cookies[0]->Value());
+  DestroyStore();
+
+  // Verify only the valid cookie remains in DB.
+  db = std::make_unique<sql::Database>(sql::test::kTestTag);
+  ASSERT_TRUE(db->Open(store_name));
+  sql::Statement verify_stmt(
+      db->GetUniqueStatement("SELECT name, value FROM cookies"));
+  ASSERT_TRUE(verify_stmt.is_valid());
+  EXPECT_TRUE(verify_stmt.Step());
+  EXPECT_EQ("sid", verify_stmt.ColumnString(0));
+  EXPECT_EQ("123", verify_stmt.ColumnString(1));
   EXPECT_FALSE(verify_stmt.Step());
 }
diff --git a/services/network/restricted_cookie_manager_unittest.cc b/services/network/restricted_cookie_manager_unittest.cc
index 0dd3fb4..a2a7ee9 100644
--- a/services/network/restricted_cookie_manager_unittest.cc
+++ b/services/network/restricted_cookie_manager_unittest.cc
@@ -1387,6 +1387,79 @@
   ASSERT_TRUE(received_bad_message());
 }
 
+TEST_P(RestrictedCookieManagerTest,
+       SetCanonicalCookieRejectEmptyNameAmbiguous) {
+  base::test::ScopedFeatureList features;
+  features.InitAndEnableFeature(
... (truncated)
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.