Chrome · Editing
CVE-2026-79196
Race in Editing
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
TEST_Pthird_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller_test.cc |
modified |
Files Changed
third_party/blink/renderer/core/editing/frame_selection.ccthird_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller_test.cc
Patch
From 4217ca7b76c7d688e5d0afddacb93128c1baffd6 Mon Sep 17 00:00:00 2001 From: Stefan Zager <[email protected]> Date: Wed, 08 Jul 2026 15:12:23 -0700 Subject: [PATCH] Verify new focused selection before triggering spell checker The previous call site to RespondToChangedSelection() was _before_ the DOM selection update had been applied. Bug: 502252964 Change-Id: I2852df5e545cd37abeda19c051f61c32962bb08d Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8063807 Commit-Queue: Stefan Zager <[email protected]> Reviewed-by: Philip Rogers <[email protected]> Cr-Commit-Position: refs/heads/main@{#1659095} --- diff --git a/third_party/blink/renderer/core/editing/frame_selection.cc b/third_party/blink/renderer/core/editing/frame_selection.cc index 0ada1e6..175c5a8a 100644 --- a/third_party/blink/renderer/core/editing/frame_selection.cc +++ b/third_party/blink/renderer/core/editing/frame_selection.cc @@ -329,7 +329,6 @@ is_handle_visible_ = should_show_handle; ScheduleVisualUpdateForVisualOverflowIfNeeded(); - frame_->GetEditor().RespondToChangedSelection(); DCHECK_EQ(current_document, GetDocument()); return true; } @@ -432,6 +431,7 @@ *Event::Create(event_type_names::kSelectionchange), TaskType::kMiscPlatformAPI); } + frame_->GetEditor().RespondToChangedSelection(); } void FrameSelection::SetSelectionForAccessibility( diff --git a/third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller_test.cc b/third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller_test.cc index 0de18d91..5379da5 100644 --- a/third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller_test.cc +++ b/third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller_test.cc @@ -334,4 +334,42 @@ } } +TEST_P(IdleSpellCheckControllerTest, ProgrammaticSelectionChangeToNewElement) { + IdleChecker().Deactivate(); + SetBodyContent( + "<div id='div1' contenteditable='true' spellcheck='true'>foo</div>" + "<div id='div2' contenteditable='true' spellcheck='true'>bar</div>"); + UpdateAllLifecyclePhasesForTest(); + EXPECT_EQ(State::kInactive, IdleChecker().GetState()); + + // Focus div1 using a mouse user gesture. + Element* div1 = QuerySelector("#div1"); + ASSERT_NE(div1, nullptr); + div1->Focus(FocusParams(SelectionBehaviorOnFocus::kRestore, + mojom::blink::FocusType::kMouse, + /*capabilities=*/nullptr)); + GetDocument().GetFrame()->Selection().SetFrameIsFocused(true); + UpdateAllLifecyclePhasesForTest(); + EXPECT_EQ(State::kHotModeRequested, IdleChecker().GetState()); + EXPECT_EQ(div1, GetDocument().FocusedElement()); + EXPECT_TRUE(div1->WasLastFocusFromUserGesture()); + + // Programmatically change selection to div2 (without user gesture). + Element* div2 = QuerySelector("#div2"); + ASSERT_NE(div2, nullptr); + EXPECT_FALSE(div2->WasLastFocusFromUserGesture()); + + GetDocument().GetFrame()->Selection().SetSelection( + SelectionInDomTree::Builder().Collapse(Position(div2, 0)).Build(), + SetSelectionOptions()); + UpdateAllLifecyclePhasesForTest(); + + EXPECT_EQ(div2, GetDocument().FocusedElement()); + if (IsUnrestricted()) { + EXPECT_EQ(State::kHotModeRequested, IdleChecker().GetState()); + } else { + EXPECT_EQ(State::kInactive, IdleChecker().GetState()); + } +} + } // namespace blink
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller_test.cc b/third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller_test.cc
index 0de18d91..5379da5 100644
--- a/third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller_test.cc
+++ b/third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller_test.cc
@@ -334,4 +334,42 @@
}
}
+TEST_P(IdleSpellCheckControllerTest, ProgrammaticSelectionChangeToNewElement) {
+ IdleChecker().Deactivate();
+ SetBodyContent(
+ "<div id='div1' contenteditable='true' spellcheck='true'>foo</div>"
+ "<div id='div2' contenteditable='true' spellcheck='true'>bar</div>");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(State::kInactive, IdleChecker().GetState());
+
+ // Focus div1 using a mouse user gesture.
+ Element* div1 = QuerySelector("#div1");
+ ASSERT_NE(div1, nullptr);
+ div1->Focus(FocusParams(SelectionBehaviorOnFocus::kRestore,
+ mojom::blink::FocusType::kMouse,
+ /*capabilities=*/nullptr));
+ GetDocument().GetFrame()->Selection().SetFrameIsFocused(true);
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(State::kHotModeRequested, IdleChecker().GetState());
+ EXPECT_EQ(div1, GetDocument().FocusedElement());
+ EXPECT_TRUE(div1->WasLastFocusFromUserGesture());
+
+ // Programmatically change selection to div2 (without user gesture).
+ Element* div2 = QuerySelector("#div2");
+ ASSERT_NE(div2, nullptr);
+ EXPECT_FALSE(div2->WasLastFocusFromUserGesture());
+
+ GetDocument().GetFrame()->Selection().SetSelection(
+ SelectionInDomTree::Builder().Collapse(Position(div2, 0)).Build(),
+ SetSelectionOptions());
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_EQ(div2, GetDocument().FocusedElement());
+ if (IsUnrestricted()) {
+ EXPECT_EQ(State::kHotModeRequested, IdleChecker().GetState());
+ } else {
+ EXPECT_EQ(State::kInactive, IdleChecker().GetState());
+ }
+}
+
} // namespace blink
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