Medium firefox Logic Error 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactmoderate
DescriptionMitigation bypass in the Networking: Cookies component
ComponentNetworking
Bug ClassLogic Error
Tracker2023615
Fix commit8fd5860e5dc1 (firefox) +23/-24
CISA KEVNot listed
CreditedSatoki Tsuji
Disclosed2026-04-21

Changed Functions

FunctionChangeNotes
for
netwerk/cookie/CookiePrefixes.cpp
modified

Files Changed

  • netwerk/cookie/CookiePrefixes.cpp
  • testing/web-platform/meta/cookies/prefix/__Host-Http.https.html.ini
diff --git a/netwerk/cookie/CookiePrefixes.cpp b/netwerk/cookie/CookiePrefixes.cpp
index 6086cb6e715..4f451abad04 100644
--- a/netwerk/cookie/CookiePrefixes.cpp
+++ b/netwerk/cookie/CookiePrefixes.cpp
@@ -15,19 +15,28 @@ struct CookiePrefix {
   std::function<bool(const CookieStruct&, bool)> mCallback;
 };
 
+// Ordered longest-prefix-first so that more specific prefixes (e.g.
+// __Host-Http-) are checked before shorter prefixes they start with (e.g.
+// __Host-), since Check() returns on the first match.
+//
+// Per RFC 6265bis §5.4, UAs MUST match these prefixes case-insensitively
+// (see Check() below), even though §4.1.3 describes them with "case-sensitive
+// match" language — that wording applies to server-side semantics, not UA
+// enforcement.
 MOZ_RUNINIT CookiePrefix gCookiePrefixes[] = {
-    {CookiePrefixes::eSecure, "__Secure-"_ns, u"__Secure-"_ns,
+    {CookiePrefixes::eHostHttp, "__Host-Http-"_ns, u"__Host-Http-"_ns,
      [](const CookieStruct& aCookieData, bool aSecureRequest) -> bool {
-       // If a cookie's name begins with a case-sensitive match for the string
-       // __Secure-, then the cookie will have been set with a Secure attribute.
-       return aSecureRequest && aCookieData.isSecure();
+       // RFC 6265bis §4.1.3: the __Host-Http- prefix requires Secure,
+       // HttpOnly, Path=/, and no Domain attribute.
+       return aSecureRequest && aCookieData.isSecure() &&
+              aCookieData.isHttpOnly() && aCookieData.host()[0] != '.' &&
+              aCookieData.path().EqualsLiteral("/");
      }},
 
     {CookiePrefixes::eHost, "__Host-"_ns, u"__Host-"_ns,
      [](const CookieStruct& aCookieData, bool aSecureRequest) -> bool {
-       // If a cookie's name begins with a case-sensitive match for the string
-       // __Host-, then the cookie will have been set with a Secure attribute, a
-       // Path attribute with a value of /, and no Domain attribute.
+       // RFC 6265bis §4.1.3: the __Host- prefix requires Secure, Path=/,
+       // and no Domain attribute.
        return aSecureRequest && aCookieData.isSecure() &&
               aCookieData.host()[0] != '.' &&
               aCookieData.path().EqualsLiteral("/");
@@ -35,22 +44,15 @@ MOZ_RUNINIT CookiePrefix gCookiePrefixes[] = {
 
     {CookiePrefixes::eHttp, "__Http-"_ns, u"__Http-"_ns,
      [](const CookieStruct& aCookieData, bool aSecureRequest) -> bool {
-       // If a cookie's name begins with a case-sensitive match for the string
-       // __Http-, then the cookie will have been set with a Secure attribute,
-       // and an HttpOnly attribute.
+       // RFC 6265bis §4.1.3: the __Http- prefix requires Secure and HttpOnly.
        return aSecureRequest && aCookieData.isSecure() &&
               aCookieData.isHttpOnly();
      }},
 
-    {CookiePrefixes::eHostHttp, "__Host-Http-"_ns, u"__Host-Http-"_ns,
+    {CookiePrefixes::eSecure, "__Secure-"_ns, u"__Secure-"_ns,
      [](const CookieStruct& aCookieData, bool aSecureRequest) -> bool {
-       // If a cookie's name begins with a case-sensitive match for the string
-       // __Host-Http-, then the cookie will have been set with a Secure
-       // attribute, an HttpOnly attribute, a Path attribute with a value of /,
-       // and no Domain attribute.
-       return aSecureRequest && aCookieData.isSecure() &&
-              aCookieData.isHttpOnly() && aCookieData.host()[0] != '.' &&
-              aCookieData.path().EqualsLiteral("/");
+       // RFC 6265bis §4.1.3: the __Secure- prefix requires Secure.
+       return aSecureRequest && aCookieData.isSecure();
      }},
 };
 
@@ -83,6 +85,9 @@ bool CookiePrefixes::Has(const nsACString& aString) {
 // static
 bool CookiePrefixes::Check(const CookieStruct& aCookieData,
                            bool aSecureRequest) {
+  // RFC 6265bis §5.4 requires UAs to match prefixes case-insensitively.
+  // This prevents servers that process cookie names case-insensitively from
+  // inadvertently accepting miscapitalized prefixes without their guarantees.
   for (CookiePrefix& prefix : gCookiePrefixes) {
     if (StringBeginsWith(aCookieData.name(), prefix.mPrefixCString,
                          nsCaseInsensitiveCStringComparator)) {
diff --git a/testing/web-platform/meta/cookies/prefix/__Host-Http.https.html.ini b/testing/web-platform/meta/cookies/prefix/__Host-Http.https.html.ini
deleted file mode 100644
index 87e1e3b10da..00000000000
--- a/testing/web-platform/meta/cookies/prefix/__Host-Http.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[__Host-Http.https.html]
-  [__Host-Http: Does not set via DOM 'Secure; Path=/']
-    expected: FAIL
-
-  [__Host-Http: Does not set via HTTP with 'Secure; Path=/']
-    expected: FAIL
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/testing/web-platform/meta/cookies/prefix/__Host-Http.https.html.ini b/testing/web-platform/meta/cookies/prefix/__Host-Http.https.html.ini
deleted file mode 100644
index 87e1e3b10da..00000000000
--- a/testing/web-platform/meta/cookies/prefix/__Host-Http.https.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[__Host-Http.https.html]
-  [__Host-Http: Does not set via DOM 'Secure; Path=/']
-    expected: FAIL
-
-  [__Host-Http: Does not set via HTTP with 'Secure; Path=/']
-    expected: FAIL
Loading diff…