Low chrome Input Validation 🔧 Commit mapped

Overview

Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactImproper input validation in Passwords
DescriptionImproper input validation in Passwords
ComponentPasswords
Bug ClassInput Validation
Tracker562999635
Fix commit27fa86b82960 (chromium/src) +123/-0
CISA KEVNot listed
CreditedGoogle
Disclosed2026-10-20

Changed Functions

FunctionChangeNotes
if
chrome/browser/ui/passwords/password_generation_popup_controller_impl.cc
modified
DropFullscreenDelegate
chrome/browser/ui/passwords/password_generation_popup_controller_impl_unittest.cc
modified
if
chrome/browser/ui/passwords/password_generation_popup_controller_impl_unittest.cc
modified
MockPasswordManagerDriver
chrome/browser/ui/passwords/password_generation_popup_controller_impl_unittest.cc
modified
TEST_F
chrome/browser/ui/passwords/password_generation_popup_controller_impl_unittest.cc
modified
BindLambdaForTesting
chrome/browser/ui/passwords/password_generation_popup_controller_impl_unittest.cc
modified

Files Changed

  • components/password_manager/core/browser/features/password_features.cc
  • components/password_manager/core/browser/features/password_features.h
  • chrome/browser/ui/passwords/password_generation_popup_controller_impl_unittest.cc
  • chrome/browser/ui/passwords/password_generation_popup_controller_impl.h
  • chrome/browser/ui/passwords/password_generation_popup_controller_impl.cc
From 27fa86b82960ac4c3d4573a6871f476ed28981c1 Mon Sep 17 00:00:00 2001
From: Rafal Godlewski <rgod@google.com>
Date: Mon, 28 Sep 2026 07:26:12 -0700
Subject: [PATCH] Drop fullscreen and check pointer lock in password generation popup

Fixed: 562999635
Change-Id: I6b197d7f44ec1fb6efeea5a68bd83972acab27ec
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8445419
Reviewed-by: Jan Keitel <jkeitel@google.com>
Reviewed-by: Maria Kazinova <kazinova@google.com>
Commit-Queue: Rafał Godlewski <rgod@google.com>
Cr-Commit-Position: refs/heads/main@{#1706091}
---
diff --git a/chrome/browser/ui/passwords/password_generation_popup_controller_impl.cc b/chrome/browser/ui/passwords/password_generation_popup_controller_impl.cc
index 3e4463c..ca1075a 100644
--- a/chrome/browser/ui/passwords/password_generation_popup_controller_impl.cc
+++ b/chrome/browser/ui/passwords/password_generation_popup_controller_impl.cc
@@ -8,6 +8,7 @@
 #include <stddef.h>
 
 #include <algorithm>
+#include <optional>
 #include <utility>
 #include <vector>
 
@@ -22,6 +23,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
+#include "chrome/browser/ui/autofill/autofill_suggestion_controller_utils.h"
 #include "chrome/browser/ui/passwords/password_generation_popup_controller.h"
 #include "chrome/browser/ui/passwords/password_generation_popup_observer.h"
 #include "chrome/browser/ui/passwords/password_generation_popup_view.h"
@@ -32,6 +34,7 @@
 #include "components/autofill/core/common/password_generation_util.h"
 #include "components/autofill/core/common/unique_ids.h"
 #include "components/input/native_web_keyboard_event.h"
+#include "components/password_manager/core/browser/features/password_features.h"
 #include "components/password_manager/core/browser/password_bubble_experiment.h"
 #include "components/password_manager/core/browser/password_generation_frame_helper.h"
 #include "components/password_manager/core/browser/password_manager.h"
@@ -46,6 +49,7 @@
 #include "content/public/browser/web_contents.h"
 #include "ui/accessibility/platform/ax_platform.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/display/types/display_constants.h"
 #include "ui/events/keycodes/keyboard_codes.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/text_utils.h"
@@ -227,6 +231,15 @@
     return;
   }
 
+  // Hide the popup if the pointer is locked to prevent untrusted interactions.
+  if (base::FeatureList::IsEnabled(
+          password_manager::features::
+              kPasswordGenerationDropFullscreenAndCheckPointerLock) &&
+      autofill::IsPointerLocked(GetWebContents())) {
+    HideImpl();
+    return;
+  }
+
   base::WeakPtr<PasswordGenerationPopupControllerImpl> weak_this = GetWeakPtr();
   if (driver_) {
     // See https://crbug.com/40053471 for when `driver_` might be null due to a
@@ -266,6 +279,33 @@
   CHECK(!current_generated_password_.empty());
   state_ = state;
 
+  if (base::FeatureList::IsEnabled(
+          password_manager::features::
+              kPasswordGenerationDropFullscreenAndCheckPointerLock)) {
+    content::WebContents* web_contents = GetWebContents();
+    if (!web_contents || autofill::IsPointerLocked(web_contents)) {
+      HideImpl();
+      return;
+    }
+
+    // Block tab fullscreen to prevent UI spoofing. The block will be released
+    // when `this` is destroyed.
+    if (!fullscreen_blocker_) {
+      base::WeakPtr<PasswordGenerationPopupControllerImpl> weak_this =
+          GetWeakPtr();
+      std::optional<base::ScopedClosureRunner> fullscreen_blocker =
+          web_contents->ForSecurityDropFullscreen(display::kInvalidDisplayId);
+      if (!weak_this) {
+        return;
+      }
+      if (!fullscreen_blocker) {
+        HideImpl();
+        return;
+      }
+      fullscreen_blocker_ = std::move(*fullscreen_blocker);
+    }
+  }
+
   if (!view_) {
     view_ = PasswordGenerationPopupView::Create(GetWeakPtr());
 
diff --git a/chrome/browser/ui/passwords/password_generation_popup_controller_impl.h b/chrome/browser/ui/passwords/password_generation_popup_controller_impl.h
index 6331192..bf8e7d5 100644
--- a/chrome/browser/ui/passwords/password_generation_popup_controller_impl.h
+++ b/chrome/browser/ui/passwords/password_generation_popup_controller_impl.h
@@ -11,6 +11,7 @@
 #include <string>
 #include <vector>
 
+#include "base/functional/callback_helpers.h"
 #include "base/i18n/rtl.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
@@ -228,6 +229,9 @@
 
   std::unique_ptr<KeyPressRegistrator> key_press_handler_manager_;
 
+  // Fullscreen block held while the popup is showing.
+  base::ScopedClosureRunner fullscreen_blocker_;
+
   base::ScopedObservation<zoom::ZoomController, zoom::ZoomObserver>
       zoom_observation_{this};
 
diff --git a/components/password_manager/core/browser/features/password_features.cc b/components/password_manager/core/browser/features/password_features.cc
index 9970daa9..05023dc1 100644
--- a/components/password_manager/core/browser/features/password_features.cc
+++ b/components/password_manager/core/browser/features/password_features.cc
@@ -166,6 +166,9 @@
 BASE_FEATURE(kPasswordFormGroupedAffiliations,
              base::FEATURE_ENABLED_BY_DEFAULT);
 
+BASE_FEATURE(kPasswordGenerationDropFullscreenAndCheckPointerLock,
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 BASE_FEATURE(kPasswordManagerLogToTerminal, base::FEATURE_DISABLED_BY_DEFAULT);
 
 BASE_FEATURE(kPasswordManagerOnDeviceEncryptionMetricsReporter,
diff --git a/components/password_manager/core/browser/features/password_features.h b/components/password_manager/core/browser/features/password_features.h
index 54604243..51bf3fb 100644
--- a/components/password_manager/core/browser/features/password_features.h
+++ b/components/password_manager/core/browser/features/password_features.h
@@ -175,6 +175,10 @@
 // Enables offering credentials for filling across grouped domains.
 BASE_DECLARE_FEATURE(kPasswordFormGroupedAffiliations);
 
+// Kill switch for dropping fullscreen and checking pointer lock before
+// showing or accepting password generation popups.
+BASE_DECLARE_FEATURE(kPasswordGenerationDropFullscreenAndCheckPointerLock);
+
 // Enables logging the content of chrome://password-manager-internals to the
 // terminal.
 BASE_DECLARE_FEATURE(kPasswordManagerLogToTerminal);
diff --git a/chrome/browser/ui/passwords/password_generation_popup_controller_impl_unittest.cc b/chrome/browser/ui/passwords/password_generation_popup_controller_impl_unittest.cc
index a33bd66..9e9375d 100644
--- a/chrome/browser/ui/passwords/password_generation_popup_controller_impl_unittest.cc
+++ b/chrome/browser/ui/passwords/password_generation_popup_controller_impl_unittest.cc
@@ -9,6 +9,7 @@
 
 #include "base/i18n/rtl.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/bind.h"
 #include "chrome/browser/ui/passwords/password_generation_popup_controller.h"
 #include "chrome/browser/ui/passwords/password_generation_popup_view.h"
 #include "chrome/grit/generated_resources.h"
@@ -21,6 +22,7 @@
 #include "components/password_manager/core/browser/stub_password_manager_client.h"
 #include "components/password_manager/core/browser/stub_password_manager_driver.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_delegate.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/geometry/rect_f.h"
@@ -41,6 +43,28 @@
       autofill::FormData(), /*input_field_empty=*/true);
 }
 
+class DropFullscreenDelegate : public content::WebContentsDelegate {
+ public:
+  explicit DropFullscreenDelegate(base::RepeatingClosure on_exit)
+      : on_exit_(std::move(on_exit)) {}
+
+  content::FullscreenState GetFullscreenState(
+      const content::WebContents* web_contents) const override {
+    content::FullscreenState state;
+    state.target_mode = content::FullscreenMode::kContent;
+    return state;
+  }
+
+  void ExitFullscreenModeForTab(content::WebContents* web_contents) override {
+    if (on_exit_) {
+      on_exit_.Run();
+    }
+  }
+
+ private:
+  base::RepeatingClosure on_exit_;
+};
+
 class MockPasswordManagerDriver
     : public password_manager::StubPasswordManagerDriver {
  public:
@@ -328,4 +352,52 @@
       PasswordGenerationPopupController::GenerationUIState::kOfferGeneration);
 }
 
+TEST_F(PasswordGenerationPopupControllerImplTest, ShowDropsFullscreen) {
+  base::WeakPtr<PasswordGenerationPopupControllerImpl> controller =
+      PasswordGenerationPopupControllerImpl::GetOrCreate(
+          /*previous=*/nullptr, ui_data().bounds, ui_data(), weak_driver(),
+          /*observer=*/nullptr, web_contents(), main_rfh());
+
+  controller->SetViewForTesting(popup_view());
+  ON_CALL(*popup_view(), UpdateBoundsAndRedrawPopup)
+      .WillByDefault(Return(true));
+
+  bool exit_fullscreen_called = false;
+  DropFullscreenDelegate delegate(
+      base::BindLambdaForTesting([&]() { exit_fullscreen_called = true; }));
+  web_contents()->SetDelegate(&delegate);
+
+  controller->GeneratePasswordValue(PasswordGenerationType::kAutomatic);
+  controller->Show(
+      PasswordGenerationPopupController::GenerationUIState::kOfferGeneration);
+
+  EXPECT_TRUE(exit_fullscreen_called);
+  web_contents()->SetDelegate(nullptr);
+}
+
+TEST_F(PasswordGenerationPopupControllerImplTest,
+       DestroyedWhileExitingFullscreenDoesNotCrash) {
+  base::WeakPtr<PasswordGenerationPopupControllerImpl> controller =
+      PasswordGenerationPopupControllerImpl::GetOrCreate(
+          /*previous=*/nullptr, ui_data().bounds, ui_data(), weak_driver(),
+          /*observer=*/nullptr, web_contents(), main_rfh());
+
+  controller->SetViewForTesting(popup_view());
+
+  DropFullscreenDelegate delegate(base::BindLambdaForTesting([&]() {
+    if (controller) {
+      static_cast<PasswordGenerationPopupController*>(controller.get())
+          ->Hide(autofill::SuggestionHidingReason::kViewDestroyed);
+    }
+  }));
+  web_contents()->SetDelegate(&delegate);
+
+  controller->GeneratePasswordValue(PasswordGenerationType::kAutomatic);
+  controller->Show(
+      PasswordGenerationPopupController::GenerationUIState::kOfferGeneration);
+
+  EXPECT_FALSE(controller);
+  web_contents()->SetDelegate(nullptr);
+}
+
 }  // namespace password_manager
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/chrome/browser/ui/passwords/password_generation_popup_controller_impl_unittest.cc b/chrome/browser/ui/passwords/password_generation_popup_controller_impl_unittest.cc
index a33bd66..9e9375d 100644
--- a/chrome/browser/ui/passwords/password_generation_popup_controller_impl_unittest.cc
+++ b/chrome/browser/ui/passwords/password_generation_popup_controller_impl_unittest.cc
@@ -9,6 +9,7 @@
 
 #include "base/i18n/rtl.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/bind.h"
 #include "chrome/browser/ui/passwords/password_generation_popup_controller.h"
 #include "chrome/browser/ui/passwords/password_generation_popup_view.h"
 #include "chrome/grit/generated_resources.h"
@@ -21,6 +22,7 @@
 #include "components/password_manager/core/browser/stub_password_manager_client.h"
 #include "components/password_manager/core/browser/stub_password_manager_driver.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_delegate.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/geometry/rect_f.h"
@@ -41,6 +43,28 @@
       autofill::FormData(), /*input_field_empty=*/true);
 }
 
+class DropFullscreenDelegate : public content::WebContentsDelegate {
+ public:
+  explicit DropFullscreenDelegate(base::RepeatingClosure on_exit)
+      : on_exit_(std::move(on_exit)) {}
+
+  content::FullscreenState GetFullscreenState(
+      const content::WebContents* web_contents) const override {
+    content::FullscreenState state;
+    state.target_mode = content::FullscreenMode::kContent;
+    return state;
+  }
+
+  void ExitFullscreenModeForTab(content::WebContents* web_contents) override {
+    if (on_exit_) {
+      on_exit_.Run();
+    }
+  }
+
+ private:
+  base::RepeatingClosure on_exit_;
+};
+
 class MockPasswordManagerDriver
     : public password_manager::StubPasswordManagerDriver {
  public:
@@ -328,4 +352,52 @@
       PasswordGenerationPopupController::GenerationUIState::kOfferGeneration);
 }
 
+TEST_F(PasswordGenerationPopupControllerImplTest, ShowDropsFullscreen) {
+  base::WeakPtr<PasswordGenerationPopupControllerImpl> controller =
+      PasswordGenerationPopupControllerImpl::GetOrCreate(
+          /*previous=*/nullptr, ui_data().bounds, ui_data(), weak_driver(),
+          /*observer=*/nullptr, web_contents(), main_rfh());
+
+  controller->SetViewForTesting(popup_view());
+  ON_CALL(*popup_view(), UpdateBoundsAndRedrawPopup)
+      .WillByDefault(Return(true));
+
+  bool exit_fullscreen_called = false;
+  DropFullscreenDelegate delegate(
+      base::BindLambdaForTesting([&]() { exit_fullscreen_called = true; }));
+  web_contents()->SetDelegate(&delegate);
+
+  controller->GeneratePasswordValue(PasswordGenerationType::kAutomatic);
+  controller->Show(
+      PasswordGenerationPopupController::GenerationUIState::kOfferGeneration);
+
+  EXPECT_TRUE(exit_fullscreen_called);
+  web_contents()->SetDelegate(nullptr);
+}
+
+TEST_F(PasswordGenerationPopupControllerImplTest,
+       DestroyedWhileExitingFullscreenDoesNotCrash) {
+  base::WeakPtr<PasswordGenerationPopupControllerImpl> controller =
+      PasswordGenerationPopupControllerImpl::GetOrCreate(
+          /*previous=*/nullptr, ui_data().bounds, ui_data(), weak_driver(),
+          /*observer=*/nullptr, web_contents(), main_rfh());
+
+  controller->SetViewForTesting(popup_view());
+
+  DropFullscreenDelegate delegate(base::BindLambdaForTesting([&]() {
+    if (controller) {
+      static_cast<PasswordGenerationPopupController*>(controller.get())
+          ->Hide(autofill::SuggestionHidingReason::kViewDestroyed);
+    }
+  }));
+  web_contents()->SetDelegate(&delegate);
+
+  controller->GeneratePasswordValue(PasswordGenerationType::kAutomatic);
+  controller->Show(
+      PasswordGenerationPopupController::GenerationUIState::kOfferGeneration);
+
+  EXPECT_FALSE(controller);
+  web_contents()->SetDelegate(nullptr);
+}
+
 }  // namespace password_manager
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.