Low watch CVSS 5.4 chrome Spoofing 🔧 Commit mapped

Overview

Low
Severity
5.4
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUI misrepresentation in TabStrip
DescriptionUI misrepresentation in TabStrip
ComponentTabStrip
Sub-componentTabDialogManager
Bug ClassSpoofing
Action tierwatch — logic/policy bug — security-relevant, no memory-unsafety
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Tracker514059780
Fix commit7f0f9b9fdd51 (chromium/src) +11/-3
CWECWE-451
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:L
CISA KEVNot listed
CreditedGoogle
Reported2026-05-17 (per vendor advisory)
Fix landed2026-08-27 (public git)
Disclosed2026-09-29
Patch gap33 days — fix public in source before the advisory

Background

`TabDialogManager` (TDM)
the object that hosts a tab-modal dialog widget for a tab and manages the input-blocking state of that tab’s web contents while the dialog is up.
`SetWebContentsBlocked`
a capability method that toggles whether a tab’s web contents accepts input; blocking it is how a modal dialog prevents the page underneath from being interacted with.
`params_->disable_input`
the flag recording whether this dialog instance requested that the tab’s web contents be input-disabled when the dialog was shown.
Legacy dialog
an older, non-TDM dialog path that can independently set the same web-contents-blocked bit on the same tab.

Root Cause Analysis

When a tab-modal dialog widget was destroyed, TabDialogManager::WidgetDestroyed unconditionally called SetWebContentsBlocked(..., /*blocked=*/false), re-enabling input on the tab’s web contents. This assumed the TDM was always the party that had blocked the contents, but the blocked bit is shared: a concurrent legacy dialog could have set it while the TDM’s own dialog did not request input disabling (params_->disable_input false). In that case the TDM’s teardown blindly clobbered the shared state, unblocking web contents that another still-present dialog expected to remain blocked, an unbalanced state reset.

The fix captures did_block_web_contents = params_ && params_->disable_input before resetting params_, and only clears the blocked bit when the TDM had actually set it, so foreign dialog state is left intact.

Key insight
The single mistake was treating a shared, ref-counted-in-spirit “web contents blocked” bit as if the TDM exclusively owned it; the fix makes the reset conditional on did_block_web_contents so the TDM only undoes the blocking it itself performed.

Attack Path

  1. Establish a legacy-dialog block A page or flow triggers a legacy (non-TDM) dialog that calls SetWebContentsBlocked(true) on the target tab, correctly disabling input on the underlying web contents.
  2. Layer a non-disabling TDM dialog A second, TDM-managed dialog is shown on the same tab whose params_->disable_input is false, so the TDM never touches the blocked bit on show. (inferred)
  3. Dismiss the TDM dialog When that TDM widget is destroyed, WidgetDestroyed runs and, pre-patch, unconditionally calls SetWebContentsBlocked(false), clearing the block the legacy dialog still relies on.
  4. Interact past a live dialog The web contents is now input-enabled while a modal dialog remains on screen, letting the page underneath be interacted with / mispresented, i.e. UI misrepresentation in the TabStrip per the advisory.

Impact Assessment

An attacker gains a spoofing / UI-misrepresentation primitive in the browser UI: input to a tab’s web contents can be re-enabled while a modal dialog is still displayed, breaking the modality guarantee. This occurs in the browser process UI layer and requires arranging overlapping legacy and TDM dialog lifetimes on the same tab. The advisory classifies this as Spoofing (UI misrepresentation in TabStrip); no memory-safety escalation is claimed or shown.

Changed Functions

FunctionChangeNotes
if
chrome/browser/ui/tabs/tab_dialog_manager.cc
modified

Files Changed

  • chrome/browser/ui/tabs/tab_dialog_manager.cc

Audit Directions

  • Shared boolean/flag ownership
    Look for teardown paths that unconditionally reset a shared UI or security state bit without first confirming this object was the one that set it.
  • Modality lifecycle races
    Audit places where multiple dialog implementations (legacy vs. new manager) can co-exist on one tab/window and both mutate the same input-blocking or visibility state.
  • Capabilities()->Set... resets
    Review other callers of capabilities()->SetWebContentsBlocked and similar toggles for balanced set/clear pairing tied to per-instance intent rather than a global assumption.
From 7f0f9b9fdd518e523072fabe73f6d95a4692e63b Mon Sep 17 00:00:00 2001
From: Allen Bauer <[email protected]>
Date: Thu, 27 Aug 2026 12:13:19 -0700
Subject: [PATCH] [TabDialogManager] Only re-enable web contents if TDM had disabled it.

This fixes an unbalanced state reset if the TDM is handling a dialog
which did not disable web contents while another legacy dialog did.
In that case, the TDM shouldn't blindly blast over the state controlling
the web contents.

Bug: 514059780
Change-Id: Iae1808523960bf874591841b74289626e9348bfa
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8307096
Reviewed-by: Keren Zhu <[email protected]>
Commit-Queue: Allen Bauer <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1687466}
---
diff --git a/chrome/browser/ui/tabs/tab_dialog_manager.cc b/chrome/browser/ui/tabs/tab_dialog_manager.cc
index 7d55c06..dcbcd60 100644
--- a/chrome/browser/ui/tabs/tab_dialog_manager.cc
+++ b/chrome/browser/ui/tabs/tab_dialog_manager.cc
@@ -405,15 +405,23 @@
 
 void TabDialogManager::WidgetDestroyed(views::Widget* widget) {
   CHECK_EQ(widget, widget_.get());
+  // Check if we had blocked the web contents in this iteration.
+  const bool did_block_web_contents = params_ && params_->disable_input;
   widget_ = nullptr;
   params_.reset();
   tab_dialog_widget_observer_.reset();
   scoped_ignore_input_events_.reset();
   web_contents_modal_dialog_host_observer_.reset();
   bounds_animation_.reset();
-  tab_interface_->GetBrowserWindowInterface()
-      ->capabilities()
-      ->SetWebContentsBlocked(tab_interface_->GetContents(), /*blocked=*/false);
+  // Only clobber the blocked web contents bit if we were also the one that
+  // blocked it. Otherwise leave it alone, since it may have been set by some
+  // other legacy dialog.
+  if (did_block_web_contents) {
+    tab_interface_->GetBrowserWindowInterface()
+        ->capabilities()
+        ->SetWebContentsBlocked(tab_interface_->GetContents(),
+                                /*blocked=*/false);
+  }
   // Resetting ScopedTabModalUI may cause the showing of a new dialog.
   // Leaving it at the end of the function to prevent its side effects
   // from being overridden.
Loading diff…