Medium CVSS 4.3 chrome Logic Error 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
4.3
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInappropriate implementation in Autofill
DescriptionInappropriate implementation in Autofill
ComponentAutofill
Sub-componentAutofill
Bug ClassLogic Error
Tracker463551850
Fix commit05a4b0a3d45c (chromium/src) +105/-15
Related commits69e11c8af383 previously mapped (not the fix) · chromium/src
CWECWE-346 (Origin validation error)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N
CISA KEVNot listed
CreditedManojkumar Jaganathan Aka TheWhiteEvil with HackerBro Technologies
Reported2025-11-25 (per vendor advisory)
Fix landed2026-06-09 (public git)
Disclosed2026-07-29
Patch gap50 days — fix public in source before the advisory
Re-mapped on 2026-10-03: our pipeline had picked the earliest commit citing this bug (69e11c8af383), which an audit found was a preparatory/helper change, not the fix. This page now points to the commit whose diff removes the bug. No root-cause analysis is published for this CVE.

Changed Functions

FunctionChangeNotes
if
chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_controller_impl.cc
modified
TEST_F
chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_controller_impl_unittest.cc
modified

Files Changed

  • chrome/browser/touch_to_fill/autofill/android/BUILD.gn
  • chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_controller_impl.cc
  • chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_controller_impl.h
  • chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_controller_impl_unittest.cc
diff --git a/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_controller_impl.cc b/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_controller_impl.cc
index 4ea1d75..fd6c9f3 100644
--- a/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_controller_impl.cc
+++ b/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_controller_impl.cc
@@ -17,6 +17,8 @@
 #include "chrome/browser/android/resource_mapper.h"
 #include "chrome/browser/touch_to_fill/autofill/android/touch_to_fill_delegate_android_impl.h"
 #include "chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_view.h"
+#include "chrome/browser/ui/android/tab_model/tab_model.h"
+#include "chrome/browser/ui/android/tab_model/tab_model_list.h"
 #include "chrome/browser/ui/autofill/autofill_suggestion_controller_utils.h"
 #include "chrome/browser/ui/autofill/payments/android_bnpl_ui_delegate.h"
 #include "components/autofill/content/browser/content_autofill_client.h"
@@ -31,6 +33,7 @@
 #include "components/autofill/core/browser/payments/payments_util.h"
 #include "components/autofill/core/browser/suggestions/suggestion.h"
 #include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/android/window_android.h"
 
@@ -97,12 +100,22 @@
     return false;
   }
 
+  // The WebContents may have lost the focus because, for example, a new tab has
+  // just been opened.
+  // Beware that this check only works as intended before TTF is shown because
+  // the bottom sheet steals the focus from the RenderWidgetHostView.
+  if (auto* rwhv = web_contents()->GetRenderWidgetHostView();
+      !rwhv || !rwhv->HasFocus()) {
+    return false;
+  }
+
   if (IsPointerLocked(web_contents())) {
     return false;
   }
 
   // The bottom sheet steals the focus from the WebContents, so we cannot rely
-  // on AutofillPopupHideHelper's focus handling.
+  // on AutofillPopupHideHelper's focus handling. Instead, we check if
+  // `IsActiveWebContents()` in the event handlers below.
   AutofillPopupHideHelper::HidingParams params = {
       .hide_on_web_contents_lost_focus = false};
 
@@ -121,6 +134,11 @@
   return true;
 }
 
+bool TouchToFillPaymentMethodControllerImpl::IsActiveWebContents() {
+  TabModel* tab_model = TabModelList::GetTabModelForWebContents(web_contents());
+  return tab_model && tab_model->GetActiveWebContents() == web_contents();
+}
+
 bool TouchToFillPaymentMethodControllerImpl::ShowPaymentMethods(
     std::unique_ptr<TouchToFillPaymentMethodView> view,
     base::WeakPtr<TouchToFillDelegate> delegate,
@@ -395,55 +413,69 @@
     JNIEnv* env,
     const std::string& unique_id,
     bool is_virtual) {
-  if (delegate_) {
-    delegate_->CreditCardSuggestionSelected(unique_id, is_virtual);
+  if (!IsActiveWebContents() || !delegate_) {
+    Hide();
+    return;
   }
+  delegate_->CreditCardSuggestionSelected(unique_id, is_virtual);
 }
 
 void TouchToFillPaymentMethodControllerImpl::BnplSuggestionSelected(
     JNIEnv* env,
     std::optional<int64_t> extracted_amount) {
-  if (delegate_) {
-    delegate_->BnplSuggestionSelected(extracted_amount);
+  if (!IsActiveWebContents() || !delegate_) {
+    Hide();
+    return;
   }
+  delegate_->BnplSuggestionSelected(extracted_amount);
 }
 
 void TouchToFillPaymentMethodControllerImpl::LocalIbanSuggestionSelected(
     JNIEnv* env,
     const std::string& guid) {
-  if (delegate_) {
-    delegate_->IbanSuggestionSelected(Iban::Guid(guid));
+  if (!IsActiveWebContents() || !delegate_) {
+    Hide();
+    return;
   }
+  delegate_->IbanSuggestionSelected(Iban::Guid(guid));
 }
 
 void TouchToFillPaymentMethodControllerImpl::ServerIbanSuggestionSelected(
     JNIEnv* env,
     long instrument_id) {
-  if (delegate_) {
-    delegate_->IbanSuggestionSelected(Iban::InstrumentId(instrument_id));
+  if (!IsActiveWebContents() || !delegate_) {
+    Hide();
+    return;
   }
+  delegate_->IbanSuggestionSelected(Iban::InstrumentId(instrument_id));
 }
 
 void TouchToFillPaymentMethodControllerImpl::LoyaltyCardSuggestionSelected(
     JNIEnv* env,
     const LoyaltyCard& loyalty_card) {
-  if (delegate_) {
-    delegate_->LoyaltyCardSuggestionSelected(loyalty_card);
+  if (!IsActiveWebContents() || !delegate_) {
+    Hide();
+    return;
   }
+  delegate_->LoyaltyCardSuggestionSelected(loyalty_card);
 }
 
 void TouchToFillPaymentMethodControllerImpl::OnBnplIssuerSuggestionSelected(
     JNIEnv* env,
     const std::string& issuer_id) {
-  if (delegate_) {
-    delegate_->OnBnplIssuerSuggestionSelected(issuer_id);
+  if (!IsActiveWebContents() || !delegate_) {
+    Hide();
+    return;
   }
+  delegate_->OnBnplIssuerSuggestionSelected(issuer_id);
 }
 
 void TouchToFillPaymentMethodControllerImpl::OnBnplTosAccepted(JNIEnv* env) {
-  if (delegate_) {
-    delegate_->OnBnplTosAccepted();
+  if (!IsActiveWebContents() || !delegate_) {
+    Hide();
+    return;
   }
+  delegate_->OnBnplTosAccepted();
 }
 
 int TouchToFillPaymentMethodControllerImpl::GetJavaResourceId(
diff --git a/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_controller_impl.h b/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_controller_impl.h
index d13f469..3dd9892d 100644
--- a/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_controller_impl.h
+++ b/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_controller_impl.h
@@ -129,6 +129,12 @@
 
  private:
   bool InitHideHelper(TouchToFillDelegate& delegate);
+
+  // The controller must ignore user actions if the associated WebContents is
+  // not active anymore. This is to handle race conditions between, for example,
+  // a new tab being opened and TTF being shown.
+  bool IsActiveWebContents();
+
   content::WebContents* web_contents();
 
   // Observes creation of ContentAutofillDrivers to inject a
diff --git a/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_controller_impl_unittest.cc b/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_controller_impl_unittest.cc
index 100fb31..00355f5 100644
--- a/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_controller_impl_unittest.cc
+++ b/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_controller_impl_unittest.cc
@@ -15,6 +15,8 @@
 #include "chrome/browser/touch_to_fill/autofill/android/touch_to_fill_delegate_android_impl.h"
 #include "chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_view.h"
 #include "chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_view_controller.h"
+#include "chrome/browser/ui/android/tab_model/tab_model_list.h"
+#include "chrome/browser/ui/android/tab_model/tab_model_test_helper.h"
 #include "chrome/browser/ui/autofill/payments/android_bnpl_ui_delegate.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "components/autofill/content/browser/test_autofill_client_injector.h"
@@ -147,6 +149,10 @@
               (std::optional<int64_t> extracted_amount),
               (override));
   MOCK_METHOD(void,
+              IbanSuggestionSelected,
+              ((std::variant<Iban::Guid, Iban::InstrumentId> backend_id)),
+              (override));
+  MOCK_METHOD(void,
               OnDismissed,
               (bool dismissed_by_user, bool should_reshow),
               (override));
@@ -191,6 +197,12 @@
 
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
+
+    tab_model_.emplace(profile());
+    TabModelList::AddTabModel(&*tab_model_);
+    tab_model_->SetWebContentsList({web_contents()});
+    tab_model_->SetIsActiveModel(true);
+
     NavigateAndCommit(GURL("about:blank"));
     FocusWebContentsOnMainFrame();
     ASSERT_TRUE(web_contents()->GetFocusedFrame());
@@ -200,6 +212,14 @@
     mock_view_ = std::make_unique<MockTouchToFillPaymentMethodViewImpl>();
   }
 
+  void AddSecondWebContents() {
+    CHECK(!second_web_contents_);
+    second_web_contents_ = content::WebContents::Create(
+        content::WebContents::CreateParams(profile()));
+    tab_model_->SetWebContentsList(
+        {second_web_contents_.get(), web_contents()});
+  }
+
   void SetUpIbanFormField() {
     some_form_data_ = autofill::test::CreateTestIbanFormData();
     some_form_ = some_form_data_.global_id();
@@ -214,6 +234,8 @@
 
   void TearDown() override {
     mock_view_.reset();
+    second_web_contents_.reset();
+    TabModelList::RemoveTabModel(&*tab_model_);
     ChromeRenderViewHostTestHarness::TearDown();
   }
 
@@ -301,6 +323,10 @@
       autofill_client_injector_;
   TestAutofillManagerInjector<TestBrowserAutofillManager>
       autofill_manager_injector_;
+
+  std::optional<TestTabModel> tab_model_;
+  std::unique_ptr<content::WebContents> second_web_contents_;
+
   FormData some_form_data_ =
       autofill::test::CreateTestCreditCardFormData(/*is_https=*/true,
                                                    /*use_month_type=*/false);
@@ -608,6 +634,30 @@
                                                      extracted_amount);
 }
 
+// Tests that accepting a (credit card) suggestion on TTF from an inactive tab
+// is a no-op.
+TEST_F(TouchToFillPaymentMethodControllerImplTest,
+       CreditCardSuggestionSelected_AbortsIfInactiveWebContents) {
+  MockTouchToFillPaymentMethodViewImpl* raw_mock_view = mock_view_.get();
+
+  OnBeforeAskForValuesToFill();
+  payment_method_controller().ShowPaymentMethods(
+      std::move(mock_view_), ttf_delegate().GetWeakPointer(), suggestions_);
+  OnAfterAskForValuesToFill();
+
+  AddSecondWebContents();
+
+  // Expect that Hide() is called on the view, and the delegate is NOT called.
+  EXPECT_CALL(*raw_mock_view, Hide());
+  EXPECT_CALL(ttf_delegate(), CreditCardSuggestionSelected).Times(0);
+
+  payment_method_controller().CreditCardSuggestionSelected(
+      /*env=*/nullptr, "some_guid", /*is_virtual=*/false);
+
+  testing::Mock::VerifyAndClearExpectations(raw_mock_view);
+  testing::Mock::VerifyAndClearExpectations(&ttf_delegate());
+}
+
 TEST_F(TouchToFillPaymentMethodControllerImplTest, ShowErrorScreenOnNewView) {
   const std::u16string title = u"Error Title";
   const std::u16string description = u"Error Description";
diff --git a/chrome/browser/touch_to_fill/autofill/android/BUILD.gn b/chrome/browser/touch_to_fill/autofill/android/BUILD.gn
index 38850beb..9252b1b 100644
--- a/chrome/browser/touch_to_fill/autofill/android/BUILD.gn
+++ b/chrome/browser/touch_to_fill/autofill/android/BUILD.gn
@@ -56,6 +56,7 @@
     "//base",
     "//chrome/android:chrome_jni_headers",
     "//chrome/browser/android:resource_mapper",
+    "//chrome/browser/ui/android/tab_model",
     "//chrome/browser/ui/autofill",
     "//chrome/browser/ui/autofill/payments",
     "//components/affiliations/core/browser:affiliations",
@@ -82,6 +83,7 @@
     ":public",
     "//base",
     "//base/test:test_support",
+    "//chrome/browser/ui/android/tab_model:test_support",
     "//chrome/browser/ui/autofill/payments",
     "//chrome/test:test_support",
     "//components/autofill/content/browser",
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_controller_impl_unittest.cc b/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_controller_impl_unittest.cc
index 100fb31..00355f5 100644
--- a/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_controller_impl_unittest.cc
+++ b/chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_controller_impl_unittest.cc
@@ -15,6 +15,8 @@
 #include "chrome/browser/touch_to_fill/autofill/android/touch_to_fill_delegate_android_impl.h"
 #include "chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_view.h"
 #include "chrome/browser/touch_to_fill/autofill/android/touch_to_fill_payment_method_view_controller.h"
+#include "chrome/browser/ui/android/tab_model/tab_model_list.h"
+#include "chrome/browser/ui/android/tab_model/tab_model_test_helper.h"
 #include "chrome/browser/ui/autofill/payments/android_bnpl_ui_delegate.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "components/autofill/content/browser/test_autofill_client_injector.h"
@@ -147,6 +149,10 @@
               (std::optional<int64_t> extracted_amount),
               (override));
   MOCK_METHOD(void,
+              IbanSuggestionSelected,
+              ((std::variant<Iban::Guid, Iban::InstrumentId> backend_id)),
+              (override));
+  MOCK_METHOD(void,
               OnDismissed,
               (bool dismissed_by_user, bool should_reshow),
               (override));
@@ -191,6 +197,12 @@
 
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
+
+    tab_model_.emplace(profile());
+    TabModelList::AddTabModel(&*tab_model_);
+    tab_model_->SetWebContentsList({web_contents()});
+    tab_model_->SetIsActiveModel(true);
+
     NavigateAndCommit(GURL("about:blank"));
     FocusWebContentsOnMainFrame();
     ASSERT_TRUE(web_contents()->GetFocusedFrame());
@@ -200,6 +212,14 @@
     mock_view_ = std::make_unique<MockTouchToFillPaymentMethodViewImpl>();
   }
 
+  void AddSecondWebContents() {
+    CHECK(!second_web_contents_);
+    second_web_contents_ = content::WebContents::Create(
+        content::WebContents::CreateParams(profile()));
+    tab_model_->SetWebContentsList(
+        {second_web_contents_.get(), web_contents()});
+  }
+
   void SetUpIbanFormField() {
     some_form_data_ = autofill::test::CreateTestIbanFormData();
     some_form_ = some_form_data_.global_id();
@@ -214,6 +234,8 @@
 
   void TearDown() override {
     mock_view_.reset();
+    second_web_contents_.reset();
+    TabModelList::RemoveTabModel(&*tab_model_);
     ChromeRenderViewHostTestHarness::TearDown();
   }
 
@@ -301,6 +323,10 @@
       autofill_client_injector_;
   TestAutofillManagerInjector<TestBrowserAutofillManager>
       autofill_manager_injector_;
+
+  std::optional<TestTabModel> tab_model_;
+  std::unique_ptr<content::WebContents> second_web_contents_;
+
   FormData some_form_data_ =
       autofill::test::CreateTestCreditCardFormData(/*is_https=*/true,
                                                    /*use_month_type=*/false);
@@ -608,6 +634,30 @@
                                                      extracted_amount);
 }
 
+// Tests that accepting a (credit card) suggestion on TTF from an inactive tab
+// is a no-op.
+TEST_F(TouchToFillPaymentMethodControllerImplTest,
+       CreditCardSuggestionSelected_AbortsIfInactiveWebContents) {
+  MockTouchToFillPaymentMethodViewImpl* raw_mock_view = mock_view_.get();
+
+  OnBeforeAskForValuesToFill();
+  payment_method_controller().ShowPaymentMethods(
+      std::move(mock_view_), ttf_delegate().GetWeakPointer(), suggestions_);
+  OnAfterAskForValuesToFill();
+
+  AddSecondWebContents();
+
+  // Expect that Hide() is called on the view, and the delegate is NOT called.
+  EXPECT_CALL(*raw_mock_view, Hide());
+  EXPECT_CALL(ttf_delegate(), CreditCardSuggestionSelected).Times(0);
+
+  payment_method_controller().CreditCardSuggestionSelected(
+      /*env=*/nullptr, "some_guid", /*is_virtual=*/false);
+
+  testing::Mock::VerifyAndClearExpectations(raw_mock_view);
+  testing::Mock::VerifyAndClearExpectations(&ttf_delegate());
+}
+
 TEST_F(TouchToFillPaymentMethodControllerImplTest, ShowErrorScreenOnNewView) {
   const std::u16string title = u"Error Title";
   const std::u16string description = u"Error Description";
Loading diff…

Original Bug Report

reported by [email protected]

Debit/Credit Card Autofill Leakage via Cross-Origin Rendering in Chrome 142.0.7444.171 for Android

Steps to reproduce the problem

  1. Visit https://attacker.hackerbro.net/exploit.html in Chrome for Android.
  2. Tap the Credit Card option and then tap Verify Info.
  3. The page redirects to https://splendorous-truffle-da6efb.netlify.app/card.html (a different origin).
  4. After the redirect, Chrome shows the stored card prompt on this cross-origin page.
  5. When the user clicks OK to populate the stored card, the card details are not filled into the currently visible page.
  6. Instead, Chrome autofills the stored card information into the attacker-controlled origin, resulting in cross-origin autofill leakage.

Problem Description

  • In Chrome version 142.0.7444.171, stored debit and credit cards are being rendered across origins. This cross-origin rendering exposes sensitive autofill data, allowing leakage when the card prompt is triggered on an external domain.

Impact:

  • Potential exposure of users’ payment card information to malicious websites via autofill.

Recommendation:

  • Restrict cross-origin access to stored payment methods and enforce same-origin policies for autofill prompts.

Summary

Debit/Credit Card Autofill Leakage via Cross-Origin Rendering in Chrome 142.0.7444.171 for Android

Custom Questions

Reporter credit:

Manojkumar Jaganathan (https://www.linkedin.com/in/manojkumar-j-7ba35b202/) Aka TheWhiteEvil (https://hackerone.com/the-white-evil) with HackerBro Technologies

Additional Data

Category: Security
Chrome Channel: Stable
Regression: No \

View on issue tracker