Chrome · Chrome for iOS
CVE-2026-14075
Logic Error in Chrome for iOS
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifios/chrome/browser/reader_mode/model/reader_mode_tab_helper.mm |
modified | |
TEST_Fios/chrome/browser/reader_mode/model/reader_mode_tab_helper_unittest.mm |
modified |
Files Changed
ios/chrome/browser/reader_mode/model/reader_mode_tab_helper.mmios/chrome/browser/reader_mode/model/reader_mode_tab_helper_unittest.mm
Patch
From fdb4fcf96972c262ecc007b562ee8ef077312ebe Mon Sep 17 00:00:00 2001 From: Quentin Pubert <[email protected]> Date: Thu, 21 May 2026 03:39:58 -0700 Subject: [PATCH] [iOS][ReaderMode] Default link forwarding to ReferrerPolicyStrictOriginWhenCrossOrigin This changes the default ReferrerPolicy used in ReaderModeContentDidCancelRequest from ReferrerPolicyDefault to ReferrerPolicyStrictOriginWhenCrossOrigin. This prevents potential Referrer-Policy bypass and URL/sensitive parameter leaks when navigating to cross-origin destinations from Reader Mode. Bug: 511808800 Change-Id: Ic3fb923f621a23d447b3fc93f0fe4f8b8be5ca1e Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7864202 Reviewed-by: Olivier Robin <[email protected]> Commit-Queue: Olivier Robin <[email protected]> Auto-Submit: Quentin Pubert <[email protected]> Commit-Queue: Quentin Pubert <[email protected]> Cr-Commit-Position: refs/heads/main@{#1634159} --- diff --git a/ios/chrome/browser/reader_mode/model/reader_mode_tab_helper.mm b/ios/chrome/browser/reader_mode/model/reader_mode_tab_helper.mm index 5221dc6f..275008d4 100644 --- a/ios/chrome/browser/reader_mode/model/reader_mode_tab_helper.mm +++ b/ios/chrome/browser/reader_mode/model/reader_mode_tab_helper.mm @@ -378,7 +378,7 @@ if (referrer_value) { NSURL* referrer_url = [NSURL URLWithString:referrer_value]; params.referrer.url = net::GURLWithNSURL(referrer_url); - params.referrer.policy = web::ReferrerPolicyDefault; + params.referrer.policy = web::ReferrerPolicyStrictOriginWhenCrossOrigin; } params.transition_type = request_info.transition_type; web_state_->GetNavigationManager()->LoadURLWithParams(params); diff --git a/ios/chrome/browser/reader_mode/model/reader_mode_tab_helper_unittest.mm b/ios/chrome/browser/reader_mode/model/reader_mode_tab_helper_unittest.mm index e5f1c9d..e10a6a4 100644 --- a/ios/chrome/browser/reader_mode/model/reader_mode_tab_helper_unittest.mm +++ b/ios/chrome/browser/reader_mode/model/reader_mode_tab_helper_unittest.mm @@ -991,6 +991,56 @@ EXPECT_EQ(0u, infobar_manager->infobars().size()); } +// Tests that when Reader Mode cancels a request, the request is forwarded to +// the navigation manager with the correct +// ReferrerPolicyStrictOriginWhenCrossOrigin policy. +TEST_F(ReaderModeTabHelperTest, ReaderModeContentDidCancelRequestForwarding) { + web_state()->WasShown(); + GURL test_url("https://test.url/"); + LoadWebpage(web_state(), test_url); + SetReaderModeState(web_state(), test_url, + ReaderModeHeuristicResult::kReaderModeEligible, "Content"); + WaitForPageLoadDelayAndRunUntilIdle(); + + // Activate Reader Mode. + reader_mode_tab_helper()->ActivateReader( + ReaderModeAccessPoint::kContextualChip); + WaitForAvailableReaderModeContentInWebState(web_state()); + + // Ensure the host tab navigation manager has not been called yet. + web::FakeNavigationManager* navigation_manager = + static_cast<web::FakeNavigationManager*>( + web_state()->GetNavigationManager()); + ASSERT_FALSE(navigation_manager->LoadURLWithParamsWasCalled()); + + // Simulate a navigation cancellation with a referrer. + NSMutableURLRequest* request = [NSMutableURLRequest + requestWithURL:[NSURL URLWithString:@"https://destination.url/"]]; + [request setValue:@"https://referrer.url/" + forHTTPHeaderField:@"Referer"]; + + web::WebStatePolicyDecider::RequestInfo request_info( + ui::PageTransition::PAGE_TRANSITION_LINK, + /*target_frame_is_main=*/true, + /*target_frame_is_cross_origin=*/true, + /*target_window_is_cross_origin=*/false, + /*is_user_initiated=*/true, + /*user_tapped_recently=*/true); + + reader_mode_tab_helper()->ReaderModeContentDidCancelRequest(nil, request, + request_info); + + // Verify that the host WebState's navigation manager loaded the request + // with web::ReferrerPolicyStrictOriginWhenCrossOrigin. + EXPECT_TRUE(navigation_manager->LoadURLWithParamsWasCalled()); + web::NavigationManager::WebLoadParams load_params = + navigation_manager->GetLastLoadURLWithParams().value(); + EXPECT_EQ(GURL("https://destination.url/"), load_params.url); + EXPECT_EQ(GURL("https://referrer.url/"), load_params.referrer.url); + EXPECT_EQ(web::ReferrerPolicyStrictOriginWhenCrossOrigin, + load_params.referrer.policy); +} + INSTANTIATE_TEST_SUITE_P( All, ReaderModeTabHelperWithEligibilityTest,
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/ios/chrome/browser/reader_mode/model/reader_mode_tab_helper_unittest.mm b/ios/chrome/browser/reader_mode/model/reader_mode_tab_helper_unittest.mm
index e5f1c9d..e10a6a4 100644
--- a/ios/chrome/browser/reader_mode/model/reader_mode_tab_helper_unittest.mm
+++ b/ios/chrome/browser/reader_mode/model/reader_mode_tab_helper_unittest.mm
@@ -991,6 +991,56 @@
EXPECT_EQ(0u, infobar_manager->infobars().size());
}
+// Tests that when Reader Mode cancels a request, the request is forwarded to
+// the navigation manager with the correct
+// ReferrerPolicyStrictOriginWhenCrossOrigin policy.
+TEST_F(ReaderModeTabHelperTest, ReaderModeContentDidCancelRequestForwarding) {
+ web_state()->WasShown();
+ GURL test_url("https://test.url/");
+ LoadWebpage(web_state(), test_url);
+ SetReaderModeState(web_state(), test_url,
+ ReaderModeHeuristicResult::kReaderModeEligible, "Content");
+ WaitForPageLoadDelayAndRunUntilIdle();
+
+ // Activate Reader Mode.
+ reader_mode_tab_helper()->ActivateReader(
+ ReaderModeAccessPoint::kContextualChip);
+ WaitForAvailableReaderModeContentInWebState(web_state());
+
+ // Ensure the host tab navigation manager has not been called yet.
+ web::FakeNavigationManager* navigation_manager =
+ static_cast<web::FakeNavigationManager*>(
+ web_state()->GetNavigationManager());
+ ASSERT_FALSE(navigation_manager->LoadURLWithParamsWasCalled());
+
+ // Simulate a navigation cancellation with a referrer.
+ NSMutableURLRequest* request = [NSMutableURLRequest
+ requestWithURL:[NSURL URLWithString:@"https://destination.url/"]];
+ [request setValue:@"https://referrer.url/"
+ forHTTPHeaderField:@"Referer"];
+
+ web::WebStatePolicyDecider::RequestInfo request_info(
+ ui::PageTransition::PAGE_TRANSITION_LINK,
+ /*target_frame_is_main=*/true,
+ /*target_frame_is_cross_origin=*/true,
+ /*target_window_is_cross_origin=*/false,
+ /*is_user_initiated=*/true,
+ /*user_tapped_recently=*/true);
+
+ reader_mode_tab_helper()->ReaderModeContentDidCancelRequest(nil, request,
+ request_info);
+
+ // Verify that the host WebState's navigation manager loaded the request
+ // with web::ReferrerPolicyStrictOriginWhenCrossOrigin.
+ EXPECT_TRUE(navigation_manager->LoadURLWithParamsWasCalled());
+ web::NavigationManager::WebLoadParams load_params =
+ navigation_manager->GetLastLoadURLWithParams().value();
+ EXPECT_EQ(GURL("https://destination.url/"), load_params.url);
+ EXPECT_EQ(GURL("https://referrer.url/"), load_params.referrer.url);
+ EXPECT_EQ(web::ReferrerPolicyStrictOriginWhenCrossOrigin,
+ load_params.referrer.policy);
+}
+
INSTANTIATE_TEST_SUITE_P(
All,
ReaderModeTabHelperWithEligibilityTest,
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.
References
On This Page