CVE-2026-11286
Overview
Files Changed
components/wallet/content/browser/content_walletable_pass_ingestion_controller.cc
Patch
From f842c3a318be6053b3a3ef7008a4783ff6b32b5f Mon Sep 17 00:00:00 2001 From: Norge Vizcay <[email protected]> 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 <[email protected]> Reviewed-by: Florian Leimgruber <[email protected]> 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()); } }
Original Bug Report
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.cccomponents/wallet/core/browser/ingestion/walletable_pass_ingestion_controller.cccomponents/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):
- Renderer Compromise: An attacker compromises a renderer process hosting an attacker-controlled site (e.g.,
https://evil.test). - Spoof DidFinishLoad IPC: From the compromised renderer, the attacker sends the
blink::mojom::LocalFrameHost::DidFinishLoadIPC, setting thevalidated_urlparameter to a target allowlisted URL (e.g.,https://trusted-merchant.com/pass). - Bypass Browser Filters: The browser receives the IPC.
WebContentsImpl::OnDidFinishLoadpasses the URL toFilterURL. Because the spoofed URL ishttps://, it passes the security checks and is broadcasted toWebContentsObservers. - Allowlist Bypass:
ContentWalletablePassIngestionController::DidFinishLoadreceives the spoofed URL and triggersWalletablePassIngestionController::StartWalletablePassDetectionFlow. The controller queries the Optimization Guide allowlist usinghttps://trusted-merchant.com/pass, which succeeds. - Data Pollution & Strike DB Poisoning: The controller proceeds to extract the actual DOM content of
https://evil.testbut pairs it with the spoofed URL (https://trusted-merchant.com/pass) when sending theWalletablePassExtractionRequestto 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 insave_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.