CVE-2025-0447
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
IN_PROC_BROWSER_TEST_Fchrome/browser/ui/content_settings/framebust_block_browsertest.cc |
modified |
Files Changed
chrome/browser/ui/content_settings/framebust_block_browsertest.cccontent/browser/renderer_host/render_frame_host_impl.cc
Patch
From 27dc50bbbf4264d20c2b42d0b2aafc9ebd63fbec Mon Sep 17 00:00:00 2001
From: Charlie Reis <creis@chromium.org>
Date: Mon, 04 Nov 2024 19:31:22 +0000
Subject: [PATCH] Filter any URLs passed to the "redirect blocked" dialogs.
The framebusting mitigation from https://crbug.com/40084719 can block
subframes from navigating the main frame cross-origin without a user
gesture. However, the dialog allows the user to manually proceed to the
URL if desired.
This URL was not adequately filtered before, allowing chrome:// and
other privileged URLs to be used even if the renderer could not nomrally
navigate to them. This CL adds the necessary filtering, which should
apply to both the desktop and Android dialogs.
Bug: 375550814
Change-Id: Icd518a869a06ad982767386d5d7a1528e6179e6c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5973403
Reviewed-by: Patrick Monette <pmonette@chromium.org>
Reviewed-by: Nate Chapin <japhet@chromium.org>
Reviewed-by: Andy Paicu <andypaicu@chromium.org>
Reviewed-by: Liam Brady <lbrady@google.com>
Auto-Submit: Charlie Reis <creis@chromium.org>
Commit-Queue: Charlie Reis <creis@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1377807}
---
diff --git a/chrome/browser/ui/content_settings/framebust_block_browsertest.cc b/chrome/browser/ui/content_settings/framebust_block_browsertest.cc
index 8ad757a..6137a4f8 100644
--- a/chrome/browser/ui/content_settings/framebust_block_browsertest.cc
+++ b/chrome/browser/ui/content_settings/framebust_block_browsertest.cc
@@ -33,6 +33,7 @@
#include "components/content_settings/core/common/content_settings_types.h"
#include "content/public/common/content_features.h"
#include "content/public/common/isolated_world_ids.h"
+#include "content/public/common/url_constants.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/fenced_frame_test_util.h"
@@ -114,8 +115,16 @@
}
bool ExecuteAndCheckBlockedRedirection() {
- EXPECT_TRUE(ui_test_utils::NavigateToURL(
- browser(), embedded_test_server()->GetURL("/iframe.html")));
+ return ExecuteAndCheckBlockedRedirection(
+ embedded_test_server()->GetURL("b.com", "/title1.html"));
+ }
+
+ // Attempts to framebust to `redirect_url` and ensures the navigation is
+ // blocked. (The test fails if not.) Returns whether the blocked URL is added
+ // to the tab helper, where the user can proceed to it if desired.
+ bool ExecuteAndCheckBlockedRedirection(const GURL& redirect_url) {
+ const GURL original_url = embedded_test_server()->GetURL("/iframe.html");
+ EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), original_url));
const GURL child_url =
embedded_test_server()->GetURL("a.com", "/title1.html");
@@ -125,9 +134,6 @@
content::ChildFrameAt(GetWebContents()->GetPrimaryMainFrame(), 0);
EXPECT_EQ(child_url, child->GetLastCommittedURL());
- const GURL redirect_url =
- embedded_test_server()->GetURL("b.com", "/title1.html");
-
base::RunLoop block_waiter;
blocked_url_added_closure_ = block_waiter.QuitClosure();
child->ExecuteJavaScriptForTests(
@@ -136,6 +142,12 @@
base::NullCallback(), content::ISOLATED_WORLD_ID_GLOBAL);
block_waiter.Run();
+ // Ensure we have not left the original page.
+ EXPECT_EQ(original_url, GetWebContents()->GetLastCommittedURL());
+
+ // Return whether the redirect URL itself ended up in the list of blocked
+ // URLs, which only happens if the renderer had the ability to navigate to
+ // the URL in the first place.
return base::Contains(GetFramebustTabHelper()->blocked_urls(),
redirect_url);
}
@@ -152,8 +164,9 @@
// to that URL.
IN_PROC_BROWSER_TEST_F(FramebustBlockBrowserTest, ModelAllowsRedirection) {
const GURL blocked_urls[] = {
- GURL(chrome::kChromeUIHistoryURL), GURL(chrome::kChromeUISettingsURL),
- GURL(chrome::kChromeUIVersionURL),
+ embedded_test_server()->GetURL("b.com", "/title1.html"),
+ embedded_test_server()->GetURL("c.com", "/title1.html"),
+ embedded_test_server()->GetURL("d.com", "/title1.html"),
};
// Signal that a blocked redirection happened.
@@ -183,7 +196,8 @@
EXPECT_TRUE(clicked_index_.has_value());
EXPECT_TRUE(clicked_url_.has_value());
EXPECT_EQ(1u, clicked_index_.value());
- EXPECT_EQ(GURL(chrome::kChromeUISettingsURL), clicked_url_.value());
+ EXPECT_EQ(embedded_test_server()->GetURL("c.com", "/title1.html"),
+ clicked_url_.value());
EXPECT_FALSE(helper->HasBlockedUrls());
EXPECT_EQ(blocked_urls[1], GetWebContents()->GetLastCommittedURL());
}
@@ -288,6 +302,30 @@
EXPECT_TRUE(ExecuteAndCheckBlockedRedirection());
}
+// Attempts to navigate to chrome:// URLs should be blocked without allowing the
+// user to proceed. Instead, the blocked URLs list includes content:kBlockedURL,
+// which is about:blank#blocked, similar to other cases where a renderer
+// attempts to navigate to an off-limits URL. See https://crbug.com/375550814.
+IN_PROC_BROWSER_TEST_F(FramebustBlockBrowserTest,
+ Framebust_WebUI_Blocked_No_Bypass) {
+ const GURL chrome_url(chrome::kChromeUISettingsURL);
+ EXPECT_FALSE(ExecuteAndCheckBlockedRedirection(chrome_url));
+ EXPECT_TRUE(base::Contains(GetFramebustTabHelper()->blocked_urls(),
+ GURL(content::kBlockedURL)));
+}
+
+// Attempts to navigate to file:// URLs should be blocked without allowing the
+// user to proceed. Instead, the blocked URLs list includes content:kBlockedURL,
+// which is about:blank#blocked, similar to other cases where a renderer
+// attempts to navigate to an off-limits URL. See https://crbug.com/375550814.
+IN_PROC_BROWSER_TEST_F(FramebustBlockBrowserTest,
+ Framebust_File_Blocked_No_Bypass) {
+ const GURL file_url("file:///");
+ EXPECT_FALSE(ExecuteAndCheckBlockedRedirection(file_url));
+ EXPECT_TRUE(base::Contains(GetFramebustTabHelper()->blocked_urls(),
+ GURL(content::kBlockedURL)));
+}
+
IN_PROC_BROWSER_TEST_F(FramebustBlockBrowserTest,
FramebustAllowedByGlobalSetting) {
HostContentSettingsMap* settings_map =
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index b7122241..21d7324 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -7674,10 +7674,18 @@
const GURL& blocked_url,
const GURL& initiator_url,
blink::mojom::NavigationBlockedReason reason) {
+ // Do not allow renderers to show off-limits URLs in the blocked dialog.
+ GURL validated_blocked_url = blocked_url;
+ GURL validated_initiator_url = initiator_url;
+ RenderProcessHost* process = GetProcess();
+ process->FilterURL(/*empty_allowed=*/false, &validated_blocked_url);
+ process->FilterURL(/*empty_allowed=*/false, &validated_initiator_url);
+
// Cross-origin navigations are not allowed in prerendering so we can not
// reach here while prerendering.
DCHECK_NE(lifecycle_state(), LifecycleStateImpl::kPrerendering);
- delegate_->OnDidBlockNavigation(blocked_url, initiator_url, reason);
+ delegate_->OnDidBlockNavigation(validated_blocked_url,
+ validated_initiator_url, reason);
}
void RenderFrameHostImpl::DidChangeLoadProgress(double load_progress) {
Regression Test / PoC
diff --git a/chrome/browser/ui/content_settings/framebust_block_browsertest.cc b/chrome/browser/ui/content_settings/framebust_block_browsertest.cc
index 8ad757a..6137a4f8 100644
--- a/chrome/browser/ui/content_settings/framebust_block_browsertest.cc
+++ b/chrome/browser/ui/content_settings/framebust_block_browsertest.cc
@@ -33,6 +33,7 @@
#include "components/content_settings/core/common/content_settings_types.h"
#include "content/public/common/content_features.h"
#include "content/public/common/isolated_world_ids.h"
+#include "content/public/common/url_constants.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/fenced_frame_test_util.h"
@@ -114,8 +115,16 @@
}
bool ExecuteAndCheckBlockedRedirection() {
- EXPECT_TRUE(ui_test_utils::NavigateToURL(
- browser(), embedded_test_server()->GetURL("/iframe.html")));
+ return ExecuteAndCheckBlockedRedirection(
+ embedded_test_server()->GetURL("b.com", "/title1.html"));
+ }
+
+ // Attempts to framebust to `redirect_url` and ensures the navigation is
+ // blocked. (The test fails if not.) Returns whether the blocked URL is added
+ // to the tab helper, where the user can proceed to it if desired.
+ bool ExecuteAndCheckBlockedRedirection(const GURL& redirect_url) {
+ const GURL original_url = embedded_test_server()->GetURL("/iframe.html");
+ EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), original_url));
const GURL child_url =
embedded_test_server()->GetURL("a.com", "/title1.html");
@@ -125,9 +134,6 @@
content::ChildFrameAt(GetWebContents()->GetPrimaryMainFrame(), 0);
EXPECT_EQ(child_url, child->GetLastCommittedURL());
- const GURL redirect_url =
- embedded_test_server()->GetURL("b.com", "/title1.html");
-
base::RunLoop block_waiter;
blocked_url_added_closure_ = block_waiter.QuitClosure();
child->ExecuteJavaScriptForTests(
@@ -136,6 +142,12 @@
base::NullCallback(), content::ISOLATED_WORLD_ID_GLOBAL);
block_waiter.Run();
+ // Ensure we have not left the original page.
+ EXPECT_EQ(original_url, GetWebContents()->GetLastCommittedURL());
+
+ // Return whether the redirect URL itself ended up in the list of blocked
+ // URLs, which only happens if the renderer had the ability to navigate to
+ // the URL in the first place.
return base::Contains(GetFramebustTabHelper()->blocked_urls(),
redirect_url);
}
@@ -152,8 +164,9 @@
// to that URL.
IN_PROC_BROWSER_TEST_F(FramebustBlockBrowserTest, ModelAllowsRedirection) {
const GURL blocked_urls[] = {
- GURL(chrome::kChromeUIHistoryURL), GURL(chrome::kChromeUISettingsURL),
- GURL(chrome::kChromeUIVersionURL),
+ embedded_test_server()->GetURL("b.com", "/title1.html"),
+ embedded_test_server()->GetURL("c.com", "/title1.html"),
+ embedded_test_server()->GetURL("d.com", "/title1.html"),
};
// Signal that a blocked redirection happened.
@@ -183,7 +196,8 @@
EXPECT_TRUE(clicked_index_.has_value());
EXPECT_TRUE(clicked_url_.has_value());
EXPECT_EQ(1u, clicked_index_.value());
- EXPECT_EQ(GURL(chrome::kChromeUISettingsURL), clicked_url_.value());
+ EXPECT_EQ(embedded_test_server()->GetURL("c.com", "/title1.html"),
+ clicked_url_.value());
EXPECT_FALSE(helper->HasBlockedUrls());
EXPECT_EQ(blocked_urls[1], GetWebContents()->GetLastCommittedURL());
}
@@ -288,6 +302,30 @@
EXPECT_TRUE(ExecuteAndCheckBlockedRedirection());
}
+// Attempts to navigate to chrome:// URLs should be blocked without allowing the
+// user to proceed. Instead, the blocked URLs list includes content:kBlockedURL,
+// which is about:blank#blocked, similar to other cases where a renderer
+// attempts to navigate to an off-limits URL. See https://crbug.com/375550814.
+IN_PROC_BROWSER_TEST_F(FramebustBlockBrowserTest,
+ Framebust_WebUI_Blocked_No_Bypass) {
+ const GURL chrome_url(chrome::kChromeUISettingsURL);
+ EXPECT_FALSE(ExecuteAndCheckBlockedRedirection(chrome_url));
+ EXPECT_TRUE(base::Contains(GetFramebustTabHelper()->blocked_urls(),
+ GURL(content::kBlockedURL)));
+}
+
+// Attempts to navigate to file:// URLs should be blocked without allowing the
+// user to proceed. Instead, the blocked URLs list includes content:kBlockedURL,
+// which is about:blank#blocked, similar to other cases where a renderer
+// attempts to navigate to an off-limits URL. See https://crbug.com/375550814.
+IN_PROC_BROWSER_TEST_F(FramebustBlockBrowserTest,
+ Framebust_File_Blocked_No_Bypass) {
+ const GURL file_url("file:///");
+ EXPECT_FALSE(ExecuteAndCheckBlockedRedirection(file_url));
+ EXPECT_TRUE(base::Contains(GetFramebustTabHelper()->blocked_urls(),
+ GURL(content::kBlockedURL)));
+}
+
IN_PROC_BROWSER_TEST_F(FramebustBlockBrowserTest,
FramebustAllowedByGlobalSetting) {
HostContentSettingsMap* settings_map =
Original Bug Report
On Chrome 130.0.6723.73 on Android: there is a way website A can automatically opens chrome://chrome-urls well via Redirect blocked function
Security Bug
Important: Please do not change the component of this bug manually.
Please READ THIS FAQ before filing a bug: https://chromium.googlesource.com/chromium/src/+/HEAD/docs/security/faq.md
Please see the following link for instructions on filing security bugs: https://www.chromium.org/Home/chromium-security/reporting-security-bugs
Reports may be eligible for reward payments under the Chrome VRP: https://g.co/chrome/vrp
NOTE: Security bugs are normally made public once a fix has been widely deployed.
VULNERABILITY DETAILS On Chrome 130.0.6723.73 on Android: there is a way website A can automatically opens chrome://chrome-urls well via Redirect blocked function.
VERSION Chrome Version: 130.0.6723.73 + [stable] Operating System: [Android 14]
REPRODUCTION CASE Please include a demonstration of the security bug, such as an attached HTML or binary file that reproduces the bug when loaded in Chrome. PLEASE make the file as small as possible and remove any content not required to demonstrate the bug, or any personal or confidential information.
Please attach files directly, not in zip or other archive formats, and if you’ve created a demonstration site please also attach the files needed to reproduce the demonstration locally.
Open the local .html file (attached), allow in the Redirect blocked notification, the URL chrome://chrome-urls can be opened well after that from the local .html file via Redirect blocked function.
FOR CRASHES, PLEASE INCLUDE THE FOLLOWING ADDITIONAL INFORMATION Type of crash: [tab, browser, etc.] Crash State: [see link above: stack trace with symbols, registers, exception record] Client ID (if relevant): [see link above]
CREDIT INFORMATION Externally reported security bugs may appear in Chrome release notes. If this bug is included, how would you like to be credited? Reporter credit: Khiem Tran