Medium firefox Logic Error 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactmoderate
DescriptionMitigation bypass in the Storage: Cache API component
ComponentDOM
Bug ClassLogic Error
Tracker2047853
Fix commit657c280dd7bc (firefox) +35/-4
CISA KEVNot listed
CreditedDavid Bors at Snyk Security Labs
Disclosed2026-08-18

Files Changed

  • dom/cache/DBSchema.cpp
  • dom/cache/TypeUtils.cpp
diff --git a/dom/cache/DBSchema.cpp b/dom/cache/DBSchema.cpp
index 98cef52a468..c38a0d81d7e 100644
--- a/dom/cache/DBSchema.cpp
+++ b/dom/cache/DBSchema.cpp
@@ -77,7 +77,7 @@ const int32_t kHackyDowngradeSchemaVersion = 25;
 const int32_t kHackyPaddingSizePresentVersion = 27;
 //
 // Update this whenever the DB schema is changed.
-const int32_t kLatestSchemaVersion = 30;
+const int32_t kLatestSchemaVersion = 31;
 // ---------
 // The following constants define the SQL schema.  These are defined in the
 // same order the SQL should be executed in CreateOrMigrateSchema().  They are
@@ -146,7 +146,8 @@ const char kTableEntries[] =
     "request_url_fragment TEXT NOT NULL, "
     "response_padding_size INTEGER NULL, "
     "request_body_disk_size INTEGER NULL, "
-    "response_body_disk_size INTEGER NULL "
+    "response_body_disk_size INTEGER NULL, "
+    "response_credentials INTEGER NOT NULL "
     // New columns must be added at the end of table to migrate and
     // validate properly.
     ")";
@@ -1745,6 +1746,7 @@ nsresult InsertEntry(mozIStorageConnection& aConn, CacheId aCacheId,
                        "response_security_info_id, "
                        "response_principal_info, "
                        "response_padding_size, "
+                       "response_credentials, "
                        "cache_id "
                        ") VALUES ("
                        ":request_method, "
@@ -1773,6 +1775,7 @@ nsresult InsertEntry(mozIStorageConnection& aConn, CacheId aCacheId,
                        ":response_security_info_id, "
                        ":response_principal_info, "
                        ":response_padding_size, "
+                       ":response_credentials, "
                        ":cache_id "
                        ");"_ns));
 
@@ -1895,6 +1898,10 @@ nsresult InsertEntry(mozIStorageConnection& aConn, CacheId aCacheId,
                                                   aResponse.paddingSize())));
     }
 
+    QM_TRY(MOZ_TO_RESULT(
+        state->BindInt32ByName("response_credentials"_ns,
+                               static_cast<int32_t>(aResponse.credentials()))));
+
     QM_TRY(MOZ_TO_RESULT(state->BindInt64ByName("cache_id"_ns, aCacheId)));
 
     QM_TRY(MOZ_TO_RESULT(state->Execute()));
@@ -2007,7 +2014,7 @@ Result<SavedResponse, nsresult> ReadResponse(mozIStorageConnection& aConn,
           "entries.response_principal_info, "
           "entries.response_padding_size, "
           "security_info.data, "
-          "entries.request_credentials "
+          "entries.response_credentials "
           "FROM entries "
           "LEFT OUTER JOIN security_info "
           "ON entries.response_security_info_id=security_info.id "
@@ -2609,6 +2616,8 @@ nsresult MigrateFrom28To29(nsIFile& aDBDir, mozIStorageConnection& aConn,
                            bool& aRewriteSchema);
 nsresult MigrateFrom29To30(nsIFile& aDBDir, mozIStorageConnection& aConn,
                            bool& aRewriteSchema);
+nsresult MigrateFrom30To31(nsIFile& aDBDir, mozIStorageConnection& aConn,
+                           bool& aRewriteSchema);
 // Configure migration functions to run for the given starting version.
 constexpr Migration sMigrationList[] = {
     Migration{15, MigrateFrom15To16}, Migration{16, MigrateFrom16To17},
@@ -2618,7 +2627,7 @@ constexpr Migration sMigrationList[] = {
     Migration{23, MigrateFrom23To24}, Migration{24, MigrateFrom24To25},
     Migration{25, MigrateFrom25To26}, Migration{26, MigrateFrom26To27},
     Migration{27, MigrateFrom27To28}, Migration{28, MigrateFrom28To29},
-    Migration{29, MigrateFrom29To30},
+    Migration{29, MigrateFrom29To30}, Migration{30, MigrateFrom30To31},
 };
 
 nsresult RewriteEntriesSchema(mozIStorageConnection& aConn) {
@@ -3279,5 +3288,24 @@ nsresult MigrateFrom29To30(nsIFile& aDBDir, mozIStorageConnection& aConn,
   return NS_OK;
 }
 
+nsresult MigrateFrom30To31(nsIFile& aDBDir, mozIStorageConnection& aConn,
+                           bool& aRewriteSchema) {
+  MOZ_ASSERT(!NS_IsMainThread());
+
+  // Existing response objects would be getting credential type set to 2,
+  // which means that these response objects can no longer be loaded by
+  // credentialless cross-origin embedders which is fine; a network fetch
+  // would need to be performed for such objects.
+  QM_TRY(MOZ_TO_RESULT(aConn.ExecuteSimpleSQL(
+      "ALTER TABLE entries "
+      "ADD COLUMN response_credentials INTEGER NOT NULL DEFAULT 2;"_ns)));
+
+  QM_TRY(MOZ_TO_RESULT(aConn.SetSchemaVersion(31)));
+
+  aRewriteSchema = true;
+
+  return NS_OK;
+}
+
 }  // anonymous namespace
 }  // namespace mozilla::dom::cache::db
diff --git a/dom/cache/TypeUtils.cpp b/dom/cache/TypeUtils.cpp
index 66720d0a711..5d06479c0b6 100644
--- a/dom/cache/TypeUtils.cpp
+++ b/dom/cache/TypeUtils.cpp
@@ -208,6 +208,9 @@ void TypeUtils::ToCacheResponseWithoutBody(CacheResponse& aOut,
 
   aOut.paddingInfo() = aIn.GetPaddingInfo();
   aOut.paddingSize() = aIn.GetPaddingSize();
+
+  // Record the credentials mode of the fetch that produced this response.
+  aOut.credentials() = aIn.GetCredentialsMode();
 }
 
 void TypeUtils::ToCacheResponse(JSContext* aCx, CacheResponse& aOut,
Loading diff…