CVE-2026-87483
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ChromeContentBrowserClientPlatformBrowserTestchrome/browser/chrome_content_browser_client_platform_browsertest.cc |
modified |
Files Changed
chrome/browser/chrome_content_browser_client.ccchrome/browser/chrome_content_browser_client_platform_browsertest.ccchrome/test/BUILD.gn
Patch
From c2ca57044b1fe69ab46bff64e914f50a389e59d6 Mon Sep 17 00:00:00 2001 From: Aman Verma <[email protected]> Date: Thu, 30 Jul 2026 10:12:19 -0700 Subject: [PATCH] Disallow background window container type on non-extension builds ChromeContentBrowserClient::CanCreateWindow() previously returned true unconditionally for WindowContainerType::BACKGROUND on non-extension builds (such as Chrome for Android) where ENABLE_EXTENSIONS_CORE is false. This allowed ordinary web content to bypass popup blocking when calling window.open(url, name, 'background'). This change explicitly returns false for WindowContainerType::BACKGROUND when ENABLE_EXTENSIONS_CORE is false, matching the behavior on Desktop where ordinary web content lacking the extension background permission is rejected. A PlatformBrowserTest is added to platform_browser_tests (included in both browser_tests and android_browsertests) to assert that calling window.open(..., 'background') from ordinary web content returns null, even when executed with transient user activation. Furthermore, it verifies that no WebContents is created and includes a positive control assertion that a standard popup without 'background' succeeds. Bug: 520201931 Change-Id: I7b532a41121c6e2fb3eec984cfd88a5e37149d51 Fixed: 520201931 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8176283 Commit-Queue: Aman Verma <[email protected]> Reviewed-by: Dana Fried <[email protected]> Cr-Commit-Position: refs/heads/main@{#1671184} --- diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index b121c619..dd11264 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc @@ -4518,9 +4518,11 @@ if (extension && !extensions::BackgroundInfo::AllowJSAccess(extension)) { *no_javascript_access = true; } -#endif return true; +#else + return false; +#endif } #if BUILDFLAG(ENABLE_EXTENSIONS_CORE) && BUILDFLAG(ENABLE_GUEST_VIEW) diff --git a/chrome/browser/chrome_content_browser_client_platform_browsertest.cc b/chrome/browser/chrome_content_browser_client_platform_browsertest.cc new file mode 100644 index 0000000..f183e34 --- /dev/null +++ b/chrome/browser/chrome_content_browser_client_platform_browsertest.cc @@ -0,0 +1,69 @@ +// Copyright 2026 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/test/base/chrome_test_utils.h" +#include "chrome/test/base/platform_browser_test.h" +#include "content/public/browser/web_contents.h" +#include "content/public/test/browser_test.h" +#include "content/public/test/browser_test_utils.h" +#include "net/dns/mock_host_resolver.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace { + +class ChromeContentBrowserClientPlatformBrowserTest + : public PlatformBrowserTest { + public: + void SetUpOnMainThread() override { + PlatformBrowserTest::SetUpOnMainThread(); + host_resolver()->AddRule("*", "127.0.0.1"); + ASSERT_TRUE(embedded_test_server()->Start()); + } + + content::WebContents* web_contents() { + return chrome_test_utils::GetActiveWebContents(this); + } +}; + +// window.open() with the 'background' window feature from ordinary web content +// must not be allowed to open a new window, even with transient user +// activation. +IN_PROC_BROWSER_TEST_F(ChromeContentBrowserClientPlatformBrowserTest, + BackgroundFeatureFromOrdinaryWebContentIsBlocked) { + ASSERT_TRUE(content::NavigateToURL( + web_contents(), embedded_test_server()->GetURL("/title1.html"))); + + const size_t initial_web_contents_count = content::GetAllWebContents().size(); + + // 1. Attempt to open a window with the 'background' feature. + // Using default EvalJs options executes with user_gesture = true, which is + // critical: without a user gesture, the standard popup blocker would reject + // the call before reaching ChromeContentBrowserClient::CanCreateWindow(). + // Even with user activation, ordinary web content lacks extension background + // permissions and must be refused when requesting 'background' window + // features. + EXPECT_EQ(true, + content::EvalJs( + web_contents(), + "window.open('/title2.html', '', 'background') === null")); + + // Verify browser-side state: no new WebContents or tab was created. + EXPECT_EQ(initial_web_contents_count, content::GetAllWebContents().size()); + + // 2. Control assertion: verify that an ordinary popup without 'background' + // succeeds with transient user activation, proving that the failure above + // was specifically due to the 'background' window feature and not because + // popups are globally disabled in the test environment. + EXPECT_EQ(true, + content::EvalJs(web_contents(), + "window.open('/title2.html', '', '') !== null")); + + // Verify that exactly one new WebContents was created by the control popup. + EXPECT_EQ(initial_web_contents_count + 1, + content::GetAllWebContents().size()); +} + +} // namespace diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index c56e0ea..24995b9 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn @@ -1021,6 +1021,7 @@ defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ] sources = [ + "../browser/chrome_content_browser_client_platform_browsertest.cc", "../browser/loadtimes_extension_bindings_browsertest.cc", "../browser/no_best_effort_tasks_browsertest.cc", "../browser/safe_browsing/client_side_detection_service_browsertest.cc",
Regression Test / PoC
diff --git a/chrome/browser/chrome_content_browser_client_platform_browsertest.cc b/chrome/browser/chrome_content_browser_client_platform_browsertest.cc
new file mode 100644
index 0000000..f183e34
--- /dev/null
+++ b/chrome/browser/chrome_content_browser_client_platform_browsertest.cc
@@ -0,0 +1,69 @@
+// Copyright 2026 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/test/base/chrome_test_utils.h"
+#include "chrome/test/base/platform_browser_test.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace {
+
+class ChromeContentBrowserClientPlatformBrowserTest
+ : public PlatformBrowserTest {
+ public:
+ void SetUpOnMainThread() override {
+ PlatformBrowserTest::SetUpOnMainThread();
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ASSERT_TRUE(embedded_test_server()->Start());
+ }
+
+ content::WebContents* web_contents() {
+ return chrome_test_utils::GetActiveWebContents(this);
+ }
+};
+
+// window.open() with the 'background' window feature from ordinary web content
+// must not be allowed to open a new window, even with transient user
+// activation.
+IN_PROC_BROWSER_TEST_F(ChromeContentBrowserClientPlatformBrowserTest,
+ BackgroundFeatureFromOrdinaryWebContentIsBlocked) {
+ ASSERT_TRUE(content::NavigateToURL(
+ web_contents(), embedded_test_server()->GetURL("/title1.html")));
+
+ const size_t initial_web_contents_count = content::GetAllWebContents().size();
+
+ // 1. Attempt to open a window with the 'background' feature.
+ // Using default EvalJs options executes with user_gesture = true, which is
+ // critical: without a user gesture, the standard popup blocker would reject
+ // the call before reaching ChromeContentBrowserClient::CanCreateWindow().
+ // Even with user activation, ordinary web content lacks extension background
+ // permissions and must be refused when requesting 'background' window
+ // features.
+ EXPECT_EQ(true,
+ content::EvalJs(
+ web_contents(),
+ "window.open('/title2.html', '', 'background') === null"));
+
+ // Verify browser-side state: no new WebContents or tab was created.
+ EXPECT_EQ(initial_web_contents_count, content::GetAllWebContents().size());
+
+ // 2. Control assertion: verify that an ordinary popup without 'background'
+ // succeeds with transient user activation, proving that the failure above
+ // was specifically due to the 'background' window feature and not because
+ // popups are globally disabled in the test environment.
+ EXPECT_EQ(true,
+ content::EvalJs(web_contents(),
+ "window.open('/title2.html', '', '') !== null"));
+
+ // Verify that exactly one new WebContents was created by the control popup.
+ EXPECT_EQ(initial_web_contents_count + 1,
+ content::GetAllWebContents().size());
+}
+
+} // namespace
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index c56e0ea..24995b9 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1021,6 +1021,7 @@
defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
sources = [
+ "../browser/chrome_content_browser_client_platform_browsertest.cc",
"../browser/loadtimes_extension_bindings_browsertest.cc",
"../browser/no_best_effort_tasks_browsertest.cc",
"../browser/safe_browsing/client_side_detection_service_browsertest.cc",
Original Bug Report
Potential popup blocker bypass on Chrome for Android via window.open background feature
Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.
Overview: A potential vulnerability in Chrome for Android allows arbitrary web pages to bypass the popup blocker and programmatically open new tabs without user activation. This occurs because the extension-only checks inside the browser client are compiled out on Android, leaving an unconditional early return when handling the ‘background’ window container type. Consequently, the popup blocking logic is bypassed, allowing automated popup spam or tab creation.
Affected files:
chrome/browser/chrome_content_browser_client.ccthird_party/blink/renderer/core/page/create_window.cccontent/renderer/render_frame_impl.cccontent/browser/renderer_host/ipc_utils.cccomponents/embedder_support/android/delegate/web_contents_delegate_android.cc
Estimated timestamp from git blame: 2014-07-16
Potential Popup Blocker Bypass on Chrome for Android via window.open('background')
Summary
We have identified a potential security vulnerability in Chrome for Android where the browser’s popup blocker can be bypassed without requiring a compromised renderer or user activation. By calling window.open(url, '_blank', 'background'), any web page can programmatically open new tabs, leading to potential popup spam, clickjacking, and phishing abuse.
Vulnerability Mechanics
When a page calls window.open(..., 'background'), the window opening flow executes as follows:
- Feature Parsing: In
third_party/blink/renderer/core/page/create_window.ccaround line 210, the renderer unconditionally parses the'background'keyword and setswindow_features.background = true. - Parameters Mapping: In
content/renderer/render_frame_impl.cc:6862,WindowFeaturesToContainerTypemaps this feature tocontent::mojom::WindowContainerType::BACKGROUNDinsideparams->window_container_type. - IPC Transfer: The renderer sends these parameters via the synchronous
CreateNewWindowIPC interface to the browser process (content/browser/renderer_host/render_frame_host_impl.cc:10274). - Browser Policy Evaluation: The browser process delegates the request validation to the content embedder’s
CanCreateWindowinterface. Inchrome/browser/chrome_content_browser_client.ccaround lines 4529–4553:Because Chrome for Android compiles without extension support (if (container_type == content::mojom::WindowContainerType::BACKGROUND) { #if BUILDFLAG(ENABLE_EXTENSIONS_CORE) // Extension-specific background permission checks ... #endif return true; }ENABLE_EXTENSIONS_COREis false), the compiler strips the permission check inside the#ifblock. This results in an unconditional earlyreturn true;for any page requesting aBACKGROUNDcontainer type. - Blocker Bypass: Due to this early return, the execution path never reaches the end of the
CanCreateWindowfunction whereConsiderForPopupBlockingandMaybeBlockPopupare invoked to block un-activated window creations. As a result, the request is unconditionally approved and processed as a normal tab creation on Android.
Potential Attack Vector
An attacker could potentially trigger this bypass from any untrusted web context by serving a page with the following snippet:
<script>
// Potential trigger vector: opens a background tab without user gesture
window.open('https://example.com/', '_blank', 'background');
</script>
Note: These steps represent a potential trigger flow. Our tooling does not currently have the capacity to dynamically execute and verify the POC on Chrome for Android.
Recommended Mitigation
We suggest the following structural changes to resolve this potential issue:
- Move the
return true;statement atchrome/browser/chrome_content_browser_client.cc:4552inside the#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)block. In environments without extensions support, the handler should fall through to standard popup blocking validation. - In
content/browser/renderer_host/ipc_utils.cc:VerifyCreateNewWindowParams, add defense-in-depth checks to validate and reject requests specifyingWindowContainerType::BACKGROUNDorPERSISTENTfrom non-privileged/non-extension renderer processes.
Evaluated with Chrome root at commit: d8b226a3be7c9c1ac9240c09e14698866c82e4ac
Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:
- If you are familiar with the severity guidelines, you may adjust the severity.
- If this is a false positive, and there’s no work to be done, please close as WAI.
- If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.
Data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.