Chrome · WebUI
CVE-2026-87506
Logic Error in WebUI
Overview
Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
IN_PROC_BROWSER_TEST_Fcontent/browser/webui/web_ui_security_browsertest.cc |
modified |
Files Changed
content/browser/renderer_host/render_frame_host_impl.cccontent/browser/webui/web_ui_impl.cccontent/browser/webui/web_ui_security_browsertest.cc
Patch
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.
References
On This Page