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 <qpubert@google.com>
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 <olivierrobin@chromium.org>
Commit-Queue: Olivier Robin <olivierrobin@chromium.org>
Auto-Submit: Quentin Pubert <qpubert@google.com>
Commit-Queue: Quentin Pubert <qpubert@google.com>
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