Medium chrome Logic Error 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactPrivilege elevation in WebUI
DescriptionPrivilege elevation in WebUI
ComponentWebUI
Bug ClassLogic Error
Tracker497551905
Fix commitd074777b1332 (chromium/src) +15/-8
CISA KEVNot listed
CreditedGoogle
Disclosed2026-09-08

Changed Functions

FunctionChangeNotes
IN_PROC_BROWSER_TEST_F
content/browser/webui/web_ui_security_browsertest.cc
modified

Files Changed

  • content/browser/renderer_host/render_frame_host_impl.cc
  • content/browser/webui/web_ui_impl.cc
  • content/browser/webui/web_ui_security_browsertest.cc
From d074777b13325b2108b4c0c2565c7c239cafa526 Mon Sep 17 00:00:00 2001
From: Fred Shih <[email protected]>
Date: Tue, 04 Aug 2026 13:21:57 -0700
Subject: [PATCH] Fix sandbox escape for chrome-untrusted://

The bug only mentioned startup, but I guess this issue persists
throughout the lifetime. This change ensures that chrome-untrusted://
does not get access to chrome:// and file:// URLs by default.

I hope this doesn't break anything...

Bug: 497551905
Change-Id: Ibb48b22505a5603cb235f76e6ff56a23bd6d7e25
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8178737
Commit-Queue: Fred Shih <[email protected]>
Reviewed-by: Rakina Zata Amni <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1673628}
---

diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 78ce44e..0ba81f0 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -13740,6 +13740,11 @@
   web_ui_type_ = new_web_ui_type;
 
   // WebUIs need the ability to request certain schemes.
+  if (!GetSiteInstance()->GetSiteInfo().site_url().SchemeIs(
+          kChromeUIUntrustedScheme)) {
+    web_ui_->AddRequestableScheme(kChromeUIScheme);
+    web_ui_->AddRequestableScheme(url::kFileScheme);
+  }
   for (const auto& scheme : web_ui_->GetRequestableSchemes()) {
     ChildProcessSecurityPolicyImpl::GetInstance()->GrantRequestScheme(
         GetProcess()->GetDeprecatedID(), scheme);
diff --git a/content/browser/webui/web_ui_impl.cc b/content/browser/webui/web_ui_impl.cc
index aa277dde..0fd5d93 100644
--- a/content/browser/webui/web_ui_impl.cc
+++ b/content/browser/webui/web_ui_impl.cc
@@ -215,8 +215,7 @@
 }
 
 WebUIImpl::WebUIImpl(WebContents* web_contents)
-    : requestable_schemes_({kChromeUIScheme, url::kFileScheme}),
-      web_contents_(web_contents),
+    : web_contents_(web_contents),
       web_contents_observer_(
           std::make_unique<WebUIMainFrameObserver>(this, web_contents_)) {
   DCHECK(web_contents_);
diff --git a/content/browser/webui/web_ui_security_browsertest.cc b/content/browser/webui/web_ui_security_browsertest.cc
index 87a9e46..f4ba4f57 100644
--- a/content/browser/webui/web_ui_security_browsertest.cc
+++ b/content/browser/webui/web_ui_security_browsertest.cc
@@ -58,7 +58,8 @@
   ScopedWebUIControllerFactoryRegistration factory_registration_{&factory_};
 };
 
-// Verify chrome-untrusted:// have no bindings.
+// Verify chrome-untrusted:// have no bindings and cannot request chrome or file
+// URLs.
 IN_PROC_BROWSER_TEST_F(WebUISecurityTest, UntrustedNoBindings) {
   auto* web_contents = shell()->web_contents();
   WebUIConfigMap::GetInstance().AddUntrustedWebUIConfig(
@@ -67,17 +68,19 @@
   const GURL untrusted_url(GetChromeUntrustedUIURL("test-host/title1.html"));
   EXPECT_TRUE(NavigateToURL(web_contents, untrusted_url));
 
+  auto process_id =
+      *shell()->web_contents()->GetPrimaryMainFrame()->GetProcess()->GetID();
   EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
-      shell()
-          ->web_contents()
-          ->GetPrimaryMainFrame()
-          ->GetProcess()
-          ->GetDeprecatedID()));
+      process_id));
   EXPECT_TRUE(shell()
                   ->web_contents()
                   ->GetPrimaryMainFrame()
                   ->GetEnabledBindings()
                   .empty());
+  EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
+      process_id, GURL("file:///etc/passwd")));
+  EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
+      process_id, GURL("chrome://version")));
 }
 
 // Loads a WebUI which does not have any bindings.
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/content/browser/webui/web_ui_security_browsertest.cc b/content/browser/webui/web_ui_security_browsertest.cc
index 87a9e46..f4ba4f57 100644
--- a/content/browser/webui/web_ui_security_browsertest.cc
+++ b/content/browser/webui/web_ui_security_browsertest.cc
@@ -58,7 +58,8 @@
   ScopedWebUIControllerFactoryRegistration factory_registration_{&factory_};
 };
 
-// Verify chrome-untrusted:// have no bindings.
+// Verify chrome-untrusted:// have no bindings and cannot request chrome or file
+// URLs.
 IN_PROC_BROWSER_TEST_F(WebUISecurityTest, UntrustedNoBindings) {
   auto* web_contents = shell()->web_contents();
   WebUIConfigMap::GetInstance().AddUntrustedWebUIConfig(
@@ -67,17 +68,19 @@
   const GURL untrusted_url(GetChromeUntrustedUIURL("test-host/title1.html"));
   EXPECT_TRUE(NavigateToURL(web_contents, untrusted_url));
 
+  auto process_id =
+      *shell()->web_contents()->GetPrimaryMainFrame()->GetProcess()->GetID();
   EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
-      shell()
-          ->web_contents()
-          ->GetPrimaryMainFrame()
-          ->GetProcess()
-          ->GetDeprecatedID()));
+      process_id));
   EXPECT_TRUE(shell()
                   ->web_contents()
                   ->GetPrimaryMainFrame()
                   ->GetEnabledBindings()
                   .empty());
+  EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
+      process_id, GURL("file:///etc/passwd")));
+  EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
+      process_id, GURL("chrome://version")));
 }
 
 // Loads a WebUI which does not have any bindings.
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.