High firefox UAF 🔧 Commit mapped

Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionUse-after-free in the DOM: Core & HTML component
ComponentDOM
Bug ClassUAF
Tracker2014596
Fix commit00b1b0666c88 (firefox) +19/-13
CISA KEVNot listed
CreditedEvyatar Ben Asher, Keane Lucas, Nicholas Carlini, Newton Cheng, Daniel Freeman, Alex Gaynor, and Joel Weinberger using Claude from Anthropic
Disclosed2026-04-21

Changed Functions

FunctionChangeNotes
for
dom/html/HTMLSlotElement.cpp
modified

Files Changed

  • dom/html/HTMLSlotElement.cpp
diff --git a/dom/html/HTMLSlotElement.cpp b/dom/html/HTMLSlotElement.cpp
index 6869887e755..b9dde8f4e4d 100644
--- a/dom/html/HTMLSlotElement.cpp
+++ b/dom/html/HTMLSlotElement.cpp
@@ -249,24 +249,26 @@ void HTMLSlotElement::Assign(const Sequence<OwningElementOrText>& aNodes) {
     // XXXsmaug Should we have a helper for
     //         https://infra.spec.whatwg.org/#ordered-set?
     if (content->GetManualSlotAssignment() != this) {
-      if (HTMLSlotElement* oldSlot = content->GetAssignedSlot()) {
-        if (changedSlots.EnsureInserted(oldSlot) && root) {
-          MOZ_ASSERT(oldSlot->GetContainingShadow() == root);
-          ShadowRoot::InvalidateStyleAndLayoutOnSubtree(oldSlot);
+      // Step 3.1: If content's manual slot assignment refers to a slot,
+      // then remove node from that slot's manually assigned nodes.
+      if (HTMLSlotElement* prevSlot = content->GetManualSlotAssignment()) {
+        ShadowRoot* prevSlotRoot = prevSlot->GetContainingShadow();
+        const bool wasAssigned = content->GetAssignedSlot() == prevSlot;
+        if (wasAssigned && prevSlotRoot &&
+            changedSlots.EnsureInserted(prevSlot)) {
+          ShadowRoot::InvalidateStyleAndLayoutOnSubtree(prevSlot);
         }
+        prevSlot->RemoveManuallyAssignedNode(*content);
       }
 
+      // Step 3.2: Set content's manual slot assignment to this.
+      content->SetManualSlotAssignment(this);
+      // Step 3.3: Append content to nodesSet.
+      mManuallyAssignedNodes.AppendElement(content);
+
       if (changedSlots.EnsureInserted(this) && root) {
         ShadowRoot::InvalidateStyleAndLayoutOnSubtree(this);
       }
-      // 3.1 (HTML Spec) If content's manual slot assignment refers to a slot,
-      // then remove node from that slot's manually assigned nodes. 3.2 (HTML
-      // Spec) Set content's manual slot assignment to this.
-      if (HTMLSlotElement* oldSlot = content->GetManualSlotAssignment()) {
-        oldSlot->RemoveManuallyAssignedNode(*content);
-      }
-      content->SetManualSlotAssignment(this);
-      mManuallyAssignedNodes.AppendElement(content);
 
       if (root && host && content->GetParent() == host) {
         // Equivalent to 4.2.2.4.3 (DOM Spec) `Set slot's assigned nodes to
@@ -288,7 +290,11 @@ void HTMLSlotElement::Assign(const Sequence<OwningElementOrText>& aNodes) {
         }
       }
     }
-    MOZ_ASSERT(changedSlots.IsEmpty());
+  }
+  // Fire slotchange for any remaining slots that are in a different shadow
+  // tree (cross-root case). The spec doesn't define an ordering here.
+  for (const auto& slot : changedSlots) {
+    slot->EnqueueSlotChangeEvent();
   }
 }
 
Loading diff…