High firefox Logic Error 🔧 Commit mapped

Overview

High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionUse-after-free in the DOM: Animation component
ComponentDOM
Bug ClassLogic Error
Tracker2081998
Fix commit8d28e6903982 (firefox) +14/-11
CISA KEVNot listed
CreditedOpenAI Codex Security (kylebot)
Disclosed2026-10-27

Changed Functions

FunctionChangeNotes
if
dom/base/Document.cpp
modified

Files Changed

  • dom/animation/ScrollTimeline.cpp
  • dom/base/Document.cpp
  • dom/base/Document.h
diff --git a/dom/animation/ScrollTimeline.cpp b/dom/animation/ScrollTimeline.cpp
index 1306ef9c7c1..293a36bfd82 100644
--- a/dom/animation/ScrollTimeline.cpp
+++ b/dom/animation/ScrollTimeline.cpp
@@ -72,6 +72,8 @@ already_AddRefed<ScrollTimeline> ScrollTimeline::Constructor(
   // <https://drafts.csswg.org/scroll-animations-1/#dom-scrolltimeline-scrolltimeline>
 
   // Step 2 -- get the source for the timeline.
+  // The scrollingElement depends on style/layout-tree in quirks mode, and we
+  // expect to get the up-to-date scrolling element, so it may flush the layout.
   Element* source = aOptions.mSource.WasPassed()
                         ? aOptions.mSource.Value().get()
                         : doc->GetScrollingElement();
diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp
index 0d2eee9d74d..e9e2dadc775 100644
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -15372,12 +15372,7 @@ already_AddRefed<Range> Document::CaretRangeFromPoint(int32_t aX, int32_t aY) {
   return range.forget();
 }
 
-bool Document::IsPotentiallyScrollableImpl(HTMLBodyElement* aBody,
-                                           Flush aFlush) {
-  if (aFlush == Flush::Yes) {
-    FlushPendingNotifications(FlushType::Frames);
-  }
-
+bool Document::IsPotentiallyScrollableImpl(HTMLBodyElement* aBody) {
   // An element that is the HTML body element is potentially scrollable if all
   // of the following conditions are true:
 
@@ -15406,15 +15401,21 @@ Element* Document::GetScrollingElementImpl(Flush aFlush) {
   if (GetCompatibilityMode() != eCompatibility_NavQuirks) {
     return GetRootElement();
   }
+
+  if (aFlush == Flush::Yes) {
+    FlushPendingNotifications(FlushType::Frames);
+  }
+  // Get the body element after we flush to make sure it is up-to-date.
   RefPtr<HTMLBodyElement> body = GetBodyElement();
-  if (body && !IsPotentiallyScrollableImpl(body, aFlush)) {
+  if (body && !IsPotentiallyScrollableImpl(body)) {
     return body;
   }
   return nullptr;
 }
 
 bool Document::IsPotentiallyScrollable(HTMLBodyElement* aBody) {
-  return IsPotentiallyScrollableImpl(aBody, Flush::Yes);
+  FlushPendingNotifications(FlushType::Frames);
+  return IsPotentiallyScrollableImpl(aBody);
 }
 
 Element* Document::GetScrollingElement() {
diff --git a/dom/base/Document.h b/dom/base/Document.h
index 052cb3a91f8..8d9a21728b5 100644
--- a/dom/base/Document.h
+++ b/dom/base/Document.h
@@ -4945,11 +4945,11 @@ class Document : public nsINode,
   // Helper for GetScrollingElement/IsScrollingElement.
   bool IsPotentiallyScrollable(HTMLBodyElement* aBody);
 
-  // Whether GetScrollingElementImpl / IsPotentiallyScrollableImpl should flush
-  // pending style and frame construction before answering.
+  // Whether GetScrollingElementImpl should flush pending style and frame
+  // construction before answering.
   enum class Flush : bool { No, Yes };
   Element* GetScrollingElementImpl(Flush);
-  bool IsPotentiallyScrollableImpl(HTMLBodyElement* aBody, Flush);
+  bool IsPotentiallyScrollableImpl(HTMLBodyElement* aBody);
 
   void MaybeStoreUserInteractionAsPermission();
 
Loading diff…