Medium chrome Logic Error 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactImproper state validation in Parser
DescriptionImproper state validation in Parser
ComponentParser
Bug ClassLogic Error
Tracker536662911
Fix commit5d50303b9695 (chromium/src) +131/-1
CISA KEVNot listed
CreditedGoogle
Disclosed2026-08-25

Changed Functions

FunctionChangeNotes
if
third_party/blink/web_tests/fast/parser/adoption-agency-cycle-crash.html
modified
if
third_party/blink/web_tests/fast/parser/adoption-agency-document-target-crash.html
modified
if
third_party/blink/web_tests/fast/parser/adoption-agency-inner-loop-cycle-crash.html
modified
if
third_party/blink/web_tests/fast/parser/adoption-agency-shadow-cycle-crash.html
modified

Files Changed

  • third_party/blink/renderer/core/html/parser/html_construction_site.cc
  • third_party/blink/renderer/core/html/parser/html_construction_site.h
  • third_party/blink/web_tests/fast/parser/adoption-agency-cycle-crash-expected.txt
  • third_party/blink/web_tests/fast/parser/adoption-agency-cycle-crash.html
  • third_party/blink/web_tests/fast/parser/adoption-agency-document-target-crash-expected.txt
  • third_party/blink/web_tests/fast/parser/adoption-agency-document-target-crash.html
  • third_party/blink/web_tests/fast/parser/adoption-agency-inner-loop-cycle-crash-expected.txt
  • third_party/blink/web_tests/fast/parser/adoption-agency-inner-loop-cycle-crash.html
  • third_party/blink/web_tests/fast/parser/adoption-agency-shadow-cycle-crash-expected.txt
  • third_party/blink/web_tests/fast/parser/adoption-agency-shadow-cycle-crash.html
From 5d50303b9695b52ec773f27a6ecb3c2ca464f532 Mon Sep 17 00:00:00 2001
From: Noam Rosenthal <nrosenthal@chromium.org>
Date: Mon, 20 Jul 2026 15:36:21 -0700
Subject: [PATCH] HTML parser: Drop a node the adoption agency cannot reinsert

Make a few check when moving around nodes with AAA.

The tests are internal temporarily until the upstream WPT and spec PR
land, but that process shouldn't delay fixing the crash.

See https://github.com/whatwg/html/pull/12709

Bug: 536662911
Change-Id: Ia357a2efea8029129b68b7fe647de4d7ba450b42
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8124514
Commit-Queue: Noam Rosenthal <nrosenthal@google.com>
Reviewed-by: David Baron <dbaron@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1664983}
---

diff --git a/third_party/blink/renderer/core/html/parser/html_construction_site.cc b/third_party/blink/renderer/core/html/parser/html_construction_site.cc
index 94ed802..8448e69 100644
--- a/third_party/blink/renderer/core/html/parser/html_construction_site.cc
+++ b/third_party/blink/renderer/core/html/parser/html_construction_site.cc
@@ -293,6 +293,21 @@
   DCHECK_EQ(task.operation,
             HTMLConstructionSiteTask::kInsertAlreadyParsedChild);
 
+  // See https://github.com/whatwg/html/pull/12709
+  if (Document* parentDoc = DynamicTo<Document>(task.parent.Get())) {
+    if (parentDoc->documentElement()) {
+      if (task.child->parentNode()) {
+        task.child->parentNode()->ParserRemoveChild(*task.child);
+      }
+      return;
+    }
+  } else if (task.child->ContainsIncludingHostElements(*task.parent)) {
+    if (task.child->parentNode()) {
+      task.child->parentNode()->ParserRemoveChild(*task.child);
+    }
+    return;
+  }
+
   Insert(task);
 }
 
@@ -1224,7 +1239,7 @@
 void HTMLConstructionSite::InsertAlreadyParsedChild(HTMLStackItem* new_parent,
                                                     HTMLStackItem* child) {
   if (new_parent->CausesFosterParenting()) {
-    FosterParent(child->GetNode());
+    FosterParentAlreadyParsedChild(child->GetNode());
     return;
   }
 
@@ -1613,6 +1628,15 @@
   QueueTask(task, true);
 }
 
+void HTMLConstructionSite::FosterParentAlreadyParsedChild(Node* child) {
+  HTMLConstructionSiteTask task(
+      HTMLConstructionSiteTask::kInsertAlreadyParsedChild);
+  FindFosterSite(task);
+  task.child = child;
+  DCHECK(task.parent);
+  QueueTask(task, true);
+}
+
 void HTMLConstructionSite::PendingText::Trace(Visitor* visitor) const {
   visitor->Trace(parent);
   visitor->Trace(next_child);
diff --git a/third_party/blink/renderer/core/html/parser/html_construction_site.h b/third_party/blink/renderer/core/html/parser/html_construction_site.h
index 987bb598..968906f 100644
--- a/third_party/blink/renderer/core/html/parser/html_construction_site.h
+++ b/third_party/blink/renderer/core/html/parser/html_construction_site.h
@@ -189,6 +189,7 @@
 
   bool ShouldFosterParent() const;
   void FosterParent(Node*);
+  void FosterParentAlreadyParsedChild(Node*);
 
   bool IndexOfFirstUnopenFormattingElement(
       unsigned& first_unopen_element_index) const;
diff --git a/third_party/blink/web_tests/fast/parser/adoption-agency-cycle-crash-expected.txt b/third_party/blink/web_tests/fast/parser/adoption-agency-cycle-crash-expected.txt
new file mode 100644
index 0000000..c2541f4
--- /dev/null
+++ b/third_party/blink/web_tests/fast/parser/adoption-agency-cycle-crash-expected.txt
@@ -0,0 +1 @@
+PASS if no crash.
diff --git a/third_party/blink/web_tests/fast/parser/adoption-agency-cycle-crash.html b/third_party/blink/web_tests/fast/parser/adoption-agency-cycle-crash.html
new file mode 100644
index 0000000..edf7f06
--- /dev/null
+++ b/third_party/blink/web_tests/fast/parser/adoption-agency-cycle-crash.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<script>
+if (window.testRunner) {
+  testRunner.dumpAsText();
+  testRunner.waitUntilDone();
+}
+</script>
+<div id=ca><b><p id=fb><script>
+window.fb = document.getElementById('fb');
+window.ca = document.getElementById('ca');
+document.body.appendChild(window.fb);
+window.fb.appendChild(window.ca);
+</script></b></div>
+<script>
+if (window.testRunner) {
+  testRunner.notifyDone();
+}
+</script>
+PASS if no crash.
diff --git a/third_party/blink/web_tests/fast/parser/adoption-agency-document-target-crash-expected.txt b/third_party/blink/web_tests/fast/parser/adoption-agency-document-target-crash-expected.txt
new file mode 100644
index 0000000..c2541f4
--- /dev/null
+++ b/third_party/blink/web_tests/fast/parser/adoption-agency-document-target-crash-expected.txt
@@ -0,0 +1 @@
+PASS if no crash.
diff --git a/third_party/blink/web_tests/fast/parser/adoption-agency-document-target-crash.html b/third_party/blink/web_tests/fast/parser/adoption-agency-document-target-crash.html
new file mode 100644
index 0000000..a2d7238
--- /dev/null
+++ b/third_party/blink/web_tests/fast/parser/adoption-agency-document-target-crash.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<script>
+if (window.testRunner) {
+  testRunner.dumpAsText();
+  testRunner.waitUntilDone();
+}
+</script>
+<table><tbody><tr><b><div id=fb><script>
+window.fb = document.getElementById('fb');
+window.other = document.implementation.createHTMLDocument('');
+window.other.documentElement.remove();
+window.other.appendChild(document.querySelector('table'));
+</script></b></table>
+<script>
+if (window.testRunner) {
+  testRunner.notifyDone();
+}
+</script>
+PASS if no crash.
diff --git a/third_party/blink/web_tests/fast/parser/adoption-agency-inner-loop-cycle-crash-expected.txt b/third_party/blink/web_tests/fast/parser/adoption-agency-inner-loop-cycle-crash-expected.txt
new file mode 100644
index 0000000..c2541f4
--- /dev/null
+++ b/third_party/blink/web_tests/fast/parser/adoption-agency-inner-loop-cycle-crash-expected.txt
@@ -0,0 +1 @@
+PASS if no crash.
diff --git a/third_party/blink/web_tests/fast/parser/adoption-agency-inner-loop-cycle-crash.html b/third_party/blink/web_tests/fast/parser/adoption-agency-inner-loop-cycle-crash.html
new file mode 100644
index 0000000..f45e242
--- /dev/null
+++ b/third_party/blink/web_tests/fast/parser/adoption-agency-inner-loop-cycle-crash.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<script>
+if (window.testRunner) {
+  testRunner.dumpAsText();
+  testRunner.waitUntilDone();
+}
+</script>
+<div id=ca><b><i><p id=fb><script>
+window.fb = document.getElementById('fb');
+window.ca = document.getElementById('ca');
+document.body.appendChild(window.fb);
+window.fb.appendChild(window.ca);
+</script></i></b></div>
+<script>
+if (window.testRunner) {
+  testRunner.notifyDone();
+}
+</script>
+PASS if no crash.
diff --git a/third_party/blink/web_tests/fast/parser/adoption-agency-shadow-cycle-crash-expected.txt b/third_party/blink/web_tests/fast/parser/adoption-agency-shadow-cycle-crash-expected.txt
new file mode 100644
index 0000000..c2541f4
--- /dev/null
+++ b/third_party/blink/web_tests/fast/parser/adoption-agency-shadow-cycle-crash-expected.txt
@@ -0,0 +1 @@
+PASS if no crash.
diff --git a/third_party/blink/web_tests/fast/parser/adoption-agency-shadow-cycle-crash.html b/third_party/blink/web_tests/fast/parser/adoption-agency-shadow-cycle-crash.html
new file mode 100644
index 0000000..1bb1fec
--- /dev/null
+++ b/third_party/blink/web_tests/fast/parser/adoption-agency-shadow-cycle-crash.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<script>
+if (window.testRunner) {
+  testRunner.dumpAsText();
+  testRunner.waitUntilDone();
+}
+</script>
+<div id=ca><b><p id=fb><script>
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/third_party/blink/web_tests/fast/parser/adoption-agency-cycle-crash-expected.txt b/third_party/blink/web_tests/fast/parser/adoption-agency-cycle-crash-expected.txt
new file mode 100644
index 0000000..c2541f4
--- /dev/null
+++ b/third_party/blink/web_tests/fast/parser/adoption-agency-cycle-crash-expected.txt
@@ -0,0 +1 @@
+PASS if no crash.
diff --git a/third_party/blink/web_tests/fast/parser/adoption-agency-cycle-crash.html b/third_party/blink/web_tests/fast/parser/adoption-agency-cycle-crash.html
new file mode 100644
index 0000000..edf7f06
--- /dev/null
+++ b/third_party/blink/web_tests/fast/parser/adoption-agency-cycle-crash.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<script>
+if (window.testRunner) {
+  testRunner.dumpAsText();
+  testRunner.waitUntilDone();
+}
+</script>
+<div id=ca><b><p id=fb><script>
+window.fb = document.getElementById('fb');
+window.ca = document.getElementById('ca');
+document.body.appendChild(window.fb);
+window.fb.appendChild(window.ca);
+</script></b></div>
+<script>
+if (window.testRunner) {
+  testRunner.notifyDone();
+}
+</script>
+PASS if no crash.
diff --git a/third_party/blink/web_tests/fast/parser/adoption-agency-document-target-crash-expected.txt b/third_party/blink/web_tests/fast/parser/adoption-agency-document-target-crash-expected.txt
new file mode 100644
index 0000000..c2541f4
--- /dev/null
+++ b/third_party/blink/web_tests/fast/parser/adoption-agency-document-target-crash-expected.txt
@@ -0,0 +1 @@
+PASS if no crash.
diff --git a/third_party/blink/web_tests/fast/parser/adoption-agency-document-target-crash.html b/third_party/blink/web_tests/fast/parser/adoption-agency-document-target-crash.html
new file mode 100644
index 0000000..a2d7238
--- /dev/null
+++ b/third_party/blink/web_tests/fast/parser/adoption-agency-document-target-crash.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<script>
+if (window.testRunner) {
+  testRunner.dumpAsText();
+  testRunner.waitUntilDone();
+}
+</script>
+<table><tbody><tr><b><div id=fb><script>
+window.fb = document.getElementById('fb');
+window.other = document.implementation.createHTMLDocument('');
+window.other.documentElement.remove();
+window.other.appendChild(document.querySelector('table'));
+</script></b></table>
+<script>
+if (window.testRunner) {
+  testRunner.notifyDone();
+}
+</script>
+PASS if no crash.
diff --git a/third_party/blink/web_tests/fast/parser/adoption-agency-inner-loop-cycle-crash-expected.txt b/third_party/blink/web_tests/fast/parser/adoption-agency-inner-loop-cycle-crash-expected.txt
new file mode 100644
index 0000000..c2541f4
--- /dev/null
+++ b/third_party/blink/web_tests/fast/parser/adoption-agency-inner-loop-cycle-crash-expected.txt
@@ -0,0 +1 @@
+PASS if no crash.
diff --git a/third_party/blink/web_tests/fast/parser/adoption-agency-inner-loop-cycle-crash.html b/third_party/blink/web_tests/fast/parser/adoption-agency-inner-loop-cycle-crash.html
new file mode 100644
index 0000000..f45e242
--- /dev/null
+++ b/third_party/blink/web_tests/fast/parser/adoption-agency-inner-loop-cycle-crash.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<script>
+if (window.testRunner) {
+  testRunner.dumpAsText();
+  testRunner.waitUntilDone();
+}
+</script>
+<div id=ca><b><i><p id=fb><script>
+window.fb = document.getElementById('fb');
+window.ca = document.getElementById('ca');
+document.body.appendChild(window.fb);
+window.fb.appendChild(window.ca);
+</script></i></b></div>
+<script>
+if (window.testRunner) {
+  testRunner.notifyDone();
+}
+</script>
+PASS if no crash.
diff --git a/third_party/blink/web_tests/fast/parser/adoption-agency-shadow-cycle-crash-expected.txt b/third_party/blink/web_tests/fast/parser/adoption-agency-shadow-cycle-crash-expected.txt
new file mode 100644
index 0000000..c2541f4
--- /dev/null
+++ b/third_party/blink/web_tests/fast/parser/adoption-agency-shadow-cycle-crash-expected.txt
@@ -0,0 +1 @@
+PASS if no crash.
diff --git a/third_party/blink/web_tests/fast/parser/adoption-agency-shadow-cycle-crash.html b/third_party/blink/web_tests/fast/parser/adoption-agency-shadow-cycle-crash.html
new file mode 100644
index 0000000..1bb1fec
--- /dev/null
+++ b/third_party/blink/web_tests/fast/parser/adoption-agency-shadow-cycle-crash.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<script>
+if (window.testRunner) {
+  testRunner.dumpAsText();
+  testRunner.waitUntilDone();
+}
+</script>
+<div id=ca><b><p id=fb><script>
+window.fb = document.getElementById('fb');
+window.ca = document.getElementById('ca');
+var host = document.createElement('span');
+var root = host.attachShadow({mode:'open'});
+document.body.appendChild(window.fb);
+window.fb.appendChild(host);
+root.appendChild(window.ca);
+</script></b></div>
+<script>
+if (window.testRunner) {
+  testRunner.notifyDone();
+}
+</script>
+PASS if no crash.
diff --git a/third_party/blink/web_tests/fast/parser/adoption-agency-template-cycle-crash-expected.txt b/third_party/blink/web_tests/fast/parser/adoption-agency-template-cycle-crash-expected.txt
new file mode 100644
index 0000000..c2541f4
--- /dev/null
+++ b/third_party/blink/web_tests/fast/parser/adoption-agency-template-cycle-crash-expected.txt
@@ -0,0 +1 @@
+PASS if no crash.
diff --git a/third_party/blink/web_tests/fast/parser/adoption-agency-template-cycle-crash.html b/third_party/blink/web_tests/fast/parser/adoption-agency-template-cycle-crash.html
new file mode 100644
index 0000000..ebd0cc5
--- /dev/null
+++ b/third_party/blink/web_tests/fast/parser/adoption-agency-template-cycle-crash.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<script>
+if (window.testRunner) {
+  testRunner.dumpAsText();
+  testRunner.waitUntilDone();
+}
+</script>
+<div id=ca><b><p id=fb><script>
+window.fb = document.getElementById('fb');
+window.ca = document.getElementById('ca');
+var tmpl = document.createElement('template');
+document.body.appendChild(window.fb);
+window.fb.appendChild(tmpl);
+tmpl.content.appendChild(window.ca);
+</script></b></div>
+<script>
+if (window.testRunner) {
+  testRunner.notifyDone();
+}
+</script>
+PASS if no crash.
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.