Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInsufficient validation of untrusted input in Wallet
DescriptionInsufficient validation of untrusted input in Wallet
ComponentWallet
Bug ClassLogic Error
Tracker502110170
Fix commitf842c3a318be (chromium/src) +1/-1
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-02

Files Changed

  • components/wallet/content/browser/content_walletable_pass_ingestion_controller.cc
From f842c3a318be6053b3a3ef7008a4783ff6b32b5f Mon Sep 17 00:00:00 2001
From: Norge Vizcay <vizcay@google.com>
Date: Thu, 16 Apr 2026 08:35:01 -0700
Subject: [PATCH] wallet: Use trusted URL in ContentWalletablePassIngestionController

ContentWalletablePassIngestionController was using the renderer-provided
validated_url in DidFinishLoad. This CL updates it to use the trusted
last committed URL from the RenderFrameHost.

Fixed: 502110170
Change-Id: Iaf2e8548e04ffbe115dbe5a7f3e02e1d1a97e8d1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7767459
Commit-Queue: Norge Vizcay <vizcay@google.com>
Reviewed-by: Florian Leimgruber <fleimgruber@google.com>
Cr-Commit-Position: refs/heads/main@{#1615896}
---

diff --git a/components/wallet/content/browser/content_walletable_pass_ingestion_controller.cc b/components/wallet/content/browser/content_walletable_pass_ingestion_controller.cc
index a6cf5b9..dd9e4f62 100644
--- a/components/wallet/content/browser/content_walletable_pass_ingestion_controller.cc
+++ b/components/wallet/content/browser/content_walletable_pass_ingestion_controller.cc
@@ -26,7 +26,7 @@
     content::RenderFrameHost* render_frame_host,
     const GURL& validated_url) {
   if (render_frame_host->IsInPrimaryMainFrame()) {
-    StartWalletablePassDetectionFlow(validated_url);
+    StartWalletablePassDetectionFlow(render_frame_host->GetLastCommittedURL());
   }
 }
 
Loading diff…

Original Bug Report

reported by vm...@google.com

Potential spoofed URL in Walletable Pass detection bypasses allowlist

Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports without the Chrome Security team.

Overview: The ContentWalletablePassIngestionController incorrectly trusts a renderer-provided URL during the DidFinishLoad event. A compromised renderer can spoof this URL to bypass the OptimizationGuide allowlist for Walletable Pass detection. This leads to cross-origin state pollution in the strike database and sends misleading context to the remote LLM executor.

Affected files:

  • components/wallet/content/browser/content_walletable_pass_ingestion_controller.cc
  • components/wallet/core/browser/ingestion/walletable_pass_ingestion_controller.cc
  • components/wallet/content/browser/walletable_pass_barcode_detector_impl.cc

Estimated timestamp from git blame: 2025-09-09

Summary

The ContentWalletablePassIngestionController implementation of WebContentsObserver::DidFinishLoad incorrectly relies on the validated_url parameter to authorize access to Wallet Pass features. This parameter originates from the blink::mojom::LocalFrameHost::DidFinishLoad IPC sent by the renderer process.

While the browser filters this URL via RenderProcessHostImpl::FilterURL, the underlying ChildProcessSecurityPolicyImpl::CanRequestURL check unconditionally allows any URL with a “web-safe” scheme (like https://). It does not verify that the URL matches the origin currently committed in the frame. Consequently, a compromised renderer can spoof any HTTPS URL, bypassing the OptimizationGuide allowlist for the Walletable Pass feature.

Potential Attack Steps

The following are suggested steps an attacker could take to exploit this vulnerability (note: this has been analyzed via code review, not a running Proof of Concept):

  1. Renderer Compromise: An attacker compromises a renderer process hosting an attacker-controlled site (e.g., https://evil.test).
  2. Spoof DidFinishLoad IPC: From the compromised renderer, the attacker sends the blink::mojom::LocalFrameHost::DidFinishLoad IPC, setting the validated_url parameter to a target allowlisted URL (e.g., https://trusted-merchant.com/pass).
  3. Bypass Browser Filters: The browser receives the IPC. WebContentsImpl::OnDidFinishLoad passes the URL to FilterURL. Because the spoofed URL is https://, it passes the security checks and is broadcasted to WebContentsObservers.
  4. Allowlist Bypass: ContentWalletablePassIngestionController::DidFinishLoad receives the spoofed URL and triggers WalletablePassIngestionController::StartWalletablePassDetectionFlow. The controller queries the Optimization Guide allowlist using https://trusted-merchant.com/pass, which succeeds.
  5. Data Pollution & Strike DB Poisoning: The controller proceeds to extract the actual DOM content of https://evil.test but pairs it with the spoofed URL (https://trusted-merchant.com/pass) when sending the WalletablePassExtractionRequest to the LLM model executor. Furthermore, if the user interacts with the resulting fake Save/Consent UI bubbles (e.g., closes or declines them), strikes are recorded in save_strike_db_ keyed by the spoofed host (trusted-merchant.com).

Impact

  • Allowlist Bypass: The feature can be triggered on arbitrary attacker-controlled sites, displaying misleading UI prompts to the user.
  • Cross-Origin State Pollution (DoS): By forcing users to reject fake prompts, an attacker can silently accumulate strikes against legitimate merchants in the local strike databases, permanently blocking the Walletable Pass feature for those sites.
  • Model Data Pollution: The remote LLM model executor receives requests containing trusted URLs paired with untrusted, attacker-controlled page content.

Recommendation

Update ContentWalletablePassIngestionController::DidFinishLoad to ignore the validated_url parameter provided by the observer callback. Instead, use the trusted browser-side state by calling render_frame_host->GetLastCommittedURL() to ensure the URL used for allowlist checks and strike database keying accurately reflects the committed document.

Evaluated with Chrome root at commit: 096fc8fdbfacf2546485756d03f160a3d04fcc9b


Results so far have been promising, but there can be wrong deductions. If this proves to be a false positive, please close as WAI; data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.

View on issue tracker