Low chrome Logic Error 🔧 Commit mapped

Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactIncorrect security UI in File Input
DescriptionIncorrect security UI in File Input
ComponentFile Input
Bug ClassLogic Error
Tracker495459838
Fix commit7a5f959341ce (chromium/src) +56/-1
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-30

Changed Functions

FunctionChangeNotes
TEST_P
content/browser/web_contents_based_canceller_unittest.cc
modified

Files Changed

  • content/browser/web_contents_based_canceller.cc
  • content/browser/web_contents_based_canceller_unittest.cc
From 7a5f959341ce9650a847690ebbe10453b1f430f9 Mon Sep 17 00:00:00 2001
From: Jack Miller <jackmil@google.com>
Date: Fri, 29 May 2026 10:49:06 -0700
Subject: [PATCH] Handle occlusion in WebContentsBasedCanceller

WebContentsBasedCanceller should consider views in both `Hidden` and
`Occluded` state as not being visible. It previously considered only
`Hidden` as not being visible.

Bug: 495459838
Change-Id: Ie99c20bb01fa744c47eb05df99f4d8779114366f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7880412
Commit-Queue: Jack Miller <jackmil@google.com>
Reviewed-by: David Bienvenu <davidbienvenu@chromium.org>
Reviewed-by: Arthur Sonzogni <arthursonzogni@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1638583}
---

diff --git a/content/browser/web_contents_based_canceller.cc b/content/browser/web_contents_based_canceller.cc
index 41db14d..51d9d865 100644
--- a/content/browser/web_contents_based_canceller.cc
+++ b/content/browser/web_contents_based_canceller.cc
@@ -47,7 +47,7 @@
 
 bool WebContentsBasedCanceller::CanShowForVisibility(Visibility visibility) {
   return condition_ != CancelCondition::kVisibility ||
-         visibility != Visibility::HIDDEN;
+         visibility == Visibility::VISIBLE;
 }
 
 bool WebContentsBasedCanceller::CanShowForRFHActiveState() {
diff --git a/content/browser/web_contents_based_canceller_unittest.cc b/content/browser/web_contents_based_canceller_unittest.cc
index 66a592dc..0f63755 100644
--- a/content/browser/web_contents_based_canceller_unittest.cc
+++ b/content/browser/web_contents_based_canceller_unittest.cc
@@ -66,6 +66,19 @@
   }
 }
 
+TEST_P(WebContentsBasedCancellerTest, CreateOccluded) {
+  web_contents()->WasOccluded();
+  switch (GetParam()) {
+    case WebContentsBasedCanceller::CancelCondition::kActiveState:
+      EXPECT_NE(nullptr, CreateWebContentsBasedCanceller());
+      break;
+    case WebContentsBasedCanceller::CancelCondition::kVisibility:
+      EXPECT_EQ(nullptr, CreateWebContentsBasedCanceller())
+          << "Dialog was allowed for an OCCLUDED WebContents.";
+      break;
+  }
+}
+
 TEST_P(WebContentsBasedCancellerTest, BecomeInactive) {
   auto ac = CreateWebContentsBasedCanceller();
   base::test::TestFuture<void> future;
@@ -97,6 +110,32 @@
   }
 }
 
+TEST_P(WebContentsBasedCancellerTest, BecomeOccluded) {
+  auto ac = CreateWebContentsBasedCanceller();
+  ASSERT_NE(nullptr, ac);
+  base::test::TestFuture<void> future;
+  ac->SetCancelCallback(future.GetCallback());
+  web_contents()->WasOccluded();
+  switch (GetParam()) {
+    case WebContentsBasedCanceller::CancelCondition::kActiveState:
+      EXPECT_FALSE(future.IsReady());
+      break;
+    case WebContentsBasedCanceller::CancelCondition::kVisibility:
+#if BUILDFLAG(IS_ANDROID)
+      // Android sends HIDDEN when picking a file. We should not cancel in this
+      // case.
+      // TODO(crbug.com/457495639): Figure out how to handle Android.
+      EXPECT_FALSE(future.IsReady());
+#else
+      EXPECT_TRUE(future.IsReady())
+          << "Dialog was NOT cancelled when WebContents became OCCLUDED. "
+          << "The file picker remains visible over a foreign foreground "
+          << "window, enabling origin spoofing.";
+#endif
+      break;
+  }
+}
+
 TEST_P(WebContentsBasedCancellerTest, InactiveBeforeSettingCallback) {
   auto ac = CreateWebContentsBasedCanceller();
   main_rfh_impl()->SetLifecycleState(
@@ -121,6 +160,22 @@
   }
 }
 
+TEST_P(WebContentsBasedCancellerTest, OccludedBeforeSettingCallback) {
+  auto ac = CreateWebContentsBasedCanceller();
+  ASSERT_NE(nullptr, ac);
+  web_contents()->WasOccluded();
+  base::test::TestFuture<void> future;
+  ac->SetCancelCallback(future.GetCallback());
+  switch (GetParam()) {
+    case WebContentsBasedCanceller::CancelCondition::kActiveState:
+      EXPECT_FALSE(future.IsReady());
+      break;
+    case WebContentsBasedCanceller::CancelCondition::kVisibility:
+      EXPECT_TRUE(future.IsReady());
+      break;
+  }
+}
+
 // Tests that destroying does not call the callback.
 TEST_P(WebContentsBasedCancellerTest, Destroy) {
   auto ac = CreateWebContentsBasedCanceller();
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/content/browser/web_contents_based_canceller_unittest.cc b/content/browser/web_contents_based_canceller_unittest.cc
index 66a592dc..0f63755 100644
--- a/content/browser/web_contents_based_canceller_unittest.cc
+++ b/content/browser/web_contents_based_canceller_unittest.cc
@@ -66,6 +66,19 @@
   }
 }
 
+TEST_P(WebContentsBasedCancellerTest, CreateOccluded) {
+  web_contents()->WasOccluded();
+  switch (GetParam()) {
+    case WebContentsBasedCanceller::CancelCondition::kActiveState:
+      EXPECT_NE(nullptr, CreateWebContentsBasedCanceller());
+      break;
+    case WebContentsBasedCanceller::CancelCondition::kVisibility:
+      EXPECT_EQ(nullptr, CreateWebContentsBasedCanceller())
+          << "Dialog was allowed for an OCCLUDED WebContents.";
+      break;
+  }
+}
+
 TEST_P(WebContentsBasedCancellerTest, BecomeInactive) {
   auto ac = CreateWebContentsBasedCanceller();
   base::test::TestFuture<void> future;
@@ -97,6 +110,32 @@
   }
 }
 
+TEST_P(WebContentsBasedCancellerTest, BecomeOccluded) {
+  auto ac = CreateWebContentsBasedCanceller();
+  ASSERT_NE(nullptr, ac);
+  base::test::TestFuture<void> future;
+  ac->SetCancelCallback(future.GetCallback());
+  web_contents()->WasOccluded();
+  switch (GetParam()) {
+    case WebContentsBasedCanceller::CancelCondition::kActiveState:
+      EXPECT_FALSE(future.IsReady());
+      break;
+    case WebContentsBasedCanceller::CancelCondition::kVisibility:
+#if BUILDFLAG(IS_ANDROID)
+      // Android sends HIDDEN when picking a file. We should not cancel in this
+      // case.
+      // TODO(crbug.com/457495639): Figure out how to handle Android.
+      EXPECT_FALSE(future.IsReady());
+#else
+      EXPECT_TRUE(future.IsReady())
+          << "Dialog was NOT cancelled when WebContents became OCCLUDED. "
+          << "The file picker remains visible over a foreign foreground "
+          << "window, enabling origin spoofing.";
+#endif
+      break;
+  }
+}
+
 TEST_P(WebContentsBasedCancellerTest, InactiveBeforeSettingCallback) {
   auto ac = CreateWebContentsBasedCanceller();
   main_rfh_impl()->SetLifecycleState(
@@ -121,6 +160,22 @@
   }
 }
 
+TEST_P(WebContentsBasedCancellerTest, OccludedBeforeSettingCallback) {
+  auto ac = CreateWebContentsBasedCanceller();
+  ASSERT_NE(nullptr, ac);
+  web_contents()->WasOccluded();
+  base::test::TestFuture<void> future;
+  ac->SetCancelCallback(future.GetCallback());
+  switch (GetParam()) {
+    case WebContentsBasedCanceller::CancelCondition::kActiveState:
+      EXPECT_FALSE(future.IsReady());
+      break;
+    case WebContentsBasedCanceller::CancelCondition::kVisibility:
+      EXPECT_TRUE(future.IsReady());
+      break;
+  }
+}
+
 // Tests that destroying does not call the callback.
 TEST_P(WebContentsBasedCancellerTest, Destroy) {
   auto ac = CreateWebContentsBasedCanceller();
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.