Low chrome Race 🔧 Commit mapped

Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactRace condition in Extensions
DescriptionRace condition in Extensions
ComponentExtensions
Bug ClassRace
Tracker533021205
Fix commitb500751eac4a (chromium/src) +42/-5
CISA KEVNot listed
CreditedGoogle
Disclosed2026-08-25

Changed Functions

FunctionChangeNotes
ExtensionApiPdfTest
chrome/browser/extensions/api/tabs/tabs_test.cc
modified

Files Changed

  • chrome/browser/extensions/api/tabs/tabs_api.cc
  • chrome/browser/extensions/api/tabs/tabs_test.cc
From b500751eac4a405ec8c988c29db0c2c7edd714a7 Mon Sep 17 00:00:00 2001
From: Devlin Cronin <[email protected]>
Date: Wed, 15 Jul 2026 11:43:37 -0700
Subject: [PATCH] [Extensions] Use GetLastCommittedURL() in tabs zoom functions

Changing the zoom settings for a tab affects the zoom settings for the
frame's origin, which uses the committed origin. However, the check
compared visible URL to see if it was a restricted URL. This would
allow an extension to zoom a tab on a restricted URL if the visible
URL differed (such as if a user navigation was under way).

Fix this so that the tabs zoom checks use the last committed URL, and
add a regression test.

Fixed: 533021205
Change-Id: I0dfbf22eec7ae1e08c0619f00c8dac9862bf3f92
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8087626
Commit-Queue: Devlin Cronin <[email protected]>
Reviewed-by: Andrea Orru <[email protected]>
Auto-Submit: Devlin Cronin <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1662763}
---

diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc
index 3e365131..efc8a9e 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -3938,7 +3938,7 @@
     return RespondNow(Error(std::move(error)));
   }
 
-  GURL url(web_contents->GetVisibleURL());
+  const GURL& url = web_contents->GetLastCommittedURL();
   if (extension()->permissions_data()->IsRestrictedUrl(url, &error)) {
     return RespondNow(Error(std::move(error)));
   }
@@ -4000,7 +4000,7 @@
     return RespondNow(Error(std::move(error)));
   }
 
-  GURL url(web_contents->GetVisibleURL());
+  const GURL& url = web_contents->GetLastCommittedURL();
   if (extension()->permissions_data()->IsRestrictedUrl(url, &error)) {
     return RespondNow(Error(std::move(error)));
   }
diff --git a/chrome/browser/extensions/api/tabs/tabs_test.cc b/chrome/browser/extensions/api/tabs/tabs_test.cc
index d3bc73d..991a9617 100644
--- a/chrome/browser/extensions/api/tabs/tabs_test.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_test.cc
@@ -3178,9 +3178,8 @@
   error = RunSetZoomSettingsExpectError(bogus_id, "manual", "per-tab");
   EXPECT_TRUE(base::MatchPattern(error, ExtensionTabUtil::kTabNotFoundError));
 
-  const char kNewTestTabArgs[] = "chrome://version";
-  params = GetOpenParams(kNewTestTabArgs);
-  web_contents = browser()->OpenURL(params, /*navigation_handle_callback=*/{});
+  const char kNewTestTabArgs[] = "chrome://version/";
+  web_contents = OpenUrlAndWaitForLoad(GURL(kNewTestTabArgs));
   tab_id = ExtensionTabUtil::GetTabId(web_contents);
 
   // Test chrome.tabs.setZoom().
@@ -3194,6 +3193,44 @@
       base::MatchPattern(error, manifest_errors::kCannotAccessChromeUrl));
 }
 
+// Tests that tabs.zoom properly looks at the committed (not visible) URLs.
+// Regression test for crbug.com/533021205.
+IN_PROC_BROWSER_TEST_F(ExtensionTabsZoomTest,
+                       ZoomingRestrictedURLsChecksCommittedURL) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  // Open a restricted URL and wait for it to load.
+  const char kRestrictedUrl[] = "chrome://version/";
+  content::WebContents* web_contents =
+      OpenUrlAndWaitForLoad(GURL(kRestrictedUrl));
+  int tab_id = ExtensionTabUtil::GetTabId(web_contents);
+
+  ASSERT_EQ(GURL(kRestrictedUrl), web_contents->GetLastCommittedURL());
+  ASSERT_EQ(GURL(kRestrictedUrl), web_contents->GetVisibleURL());
+
+  // Start a browser-initiated navigation to an unrestricted URL, but do not
+  // wait for it to commit.
+  GURL unrestricted_url = embedded_test_server()->GetURL("/title1.html");
+  content::NavigationController::LoadURLParams load_params(unrestricted_url);
+  web_contents->GetController().LoadURLWithParams(load_params);
+
+  // The visible URL should update immediately to the pending navigation target.
+  ASSERT_EQ(unrestricted_url, web_contents->GetVisibleURL());
+  // The committed URL should still be the restricted one.
+  ASSERT_EQ(GURL(kRestrictedUrl), web_contents->GetLastCommittedURL());
+
+  // Attempt to set zoom. It should fail because the committed URL is
+  // restricted.
+  std::string error = RunSetZoomExpectError(tab_id, 3.14159);
+  EXPECT_TRUE(
+      base::MatchPattern(error, manifest_errors::kCannotAccessChromeUrl));
+
+  // Attempt to set zoom settings. It should also fail.
+  error = RunSetZoomSettingsExpectError(tab_id, "manual", "per-tab");
+  EXPECT_TRUE(
+      base::MatchPattern(error, manifest_errors::kCannotAccessChromeUrl));
+}
+
 #if BUILDFLAG(ENABLE_PDF)
 class ExtensionApiPdfTest : public base::test::WithFeatureOverride,
                             public PDFExtensionTestBase {
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/chrome/browser/extensions/api/tabs/tabs_test.cc b/chrome/browser/extensions/api/tabs/tabs_test.cc
index d3bc73d..991a9617 100644
--- a/chrome/browser/extensions/api/tabs/tabs_test.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_test.cc
@@ -3178,9 +3178,8 @@
   error = RunSetZoomSettingsExpectError(bogus_id, "manual", "per-tab");
   EXPECT_TRUE(base::MatchPattern(error, ExtensionTabUtil::kTabNotFoundError));
 
-  const char kNewTestTabArgs[] = "chrome://version";
-  params = GetOpenParams(kNewTestTabArgs);
-  web_contents = browser()->OpenURL(params, /*navigation_handle_callback=*/{});
+  const char kNewTestTabArgs[] = "chrome://version/";
+  web_contents = OpenUrlAndWaitForLoad(GURL(kNewTestTabArgs));
   tab_id = ExtensionTabUtil::GetTabId(web_contents);
 
   // Test chrome.tabs.setZoom().
@@ -3194,6 +3193,44 @@
       base::MatchPattern(error, manifest_errors::kCannotAccessChromeUrl));
 }
 
+// Tests that tabs.zoom properly looks at the committed (not visible) URLs.
+// Regression test for crbug.com/533021205.
+IN_PROC_BROWSER_TEST_F(ExtensionTabsZoomTest,
+                       ZoomingRestrictedURLsChecksCommittedURL) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  // Open a restricted URL and wait for it to load.
+  const char kRestrictedUrl[] = "chrome://version/";
+  content::WebContents* web_contents =
+      OpenUrlAndWaitForLoad(GURL(kRestrictedUrl));
+  int tab_id = ExtensionTabUtil::GetTabId(web_contents);
+
+  ASSERT_EQ(GURL(kRestrictedUrl), web_contents->GetLastCommittedURL());
+  ASSERT_EQ(GURL(kRestrictedUrl), web_contents->GetVisibleURL());
+
+  // Start a browser-initiated navigation to an unrestricted URL, but do not
+  // wait for it to commit.
+  GURL unrestricted_url = embedded_test_server()->GetURL("/title1.html");
+  content::NavigationController::LoadURLParams load_params(unrestricted_url);
+  web_contents->GetController().LoadURLWithParams(load_params);
+
+  // The visible URL should update immediately to the pending navigation target.
+  ASSERT_EQ(unrestricted_url, web_contents->GetVisibleURL());
+  // The committed URL should still be the restricted one.
+  ASSERT_EQ(GURL(kRestrictedUrl), web_contents->GetLastCommittedURL());
+
+  // Attempt to set zoom. It should fail because the committed URL is
+  // restricted.
+  std::string error = RunSetZoomExpectError(tab_id, 3.14159);
+  EXPECT_TRUE(
+      base::MatchPattern(error, manifest_errors::kCannotAccessChromeUrl));
+
+  // Attempt to set zoom settings. It should also fail.
+  error = RunSetZoomSettingsExpectError(tab_id, "manual", "per-tab");
+  EXPECT_TRUE(
+      base::MatchPattern(error, manifest_errors::kCannotAccessChromeUrl));
+}
+
 #if BUILDFLAG(ENABLE_PDF)
 class ExtensionApiPdfTest : public base::test::WithFeatureOverride,
                             public PDFExtensionTestBase {
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.