Medium chrome Logic Error 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactIncorrect authorization in Browser
DescriptionIncorrect authorization in Browser
ComponentBrowser
Bug ClassLogic Error
Tracker520201931
Fix commitc2ca57044b1f (chromium/src) +73/-1
CISA KEVNot listed
CreditedGoogle
Disclosed2026-09-08

Changed Functions

FunctionChangeNotes
ChromeContentBrowserClientPlatformBrowserTest
chrome/browser/chrome_content_browser_client_platform_browsertest.cc
modified

Files Changed

  • chrome/browser/chrome_content_browser_client.cc
  • chrome/browser/chrome_content_browser_client_platform_browsertest.cc
  • chrome/test/BUILD.gn
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",
Loading diff…

Regression Test / PoC

shipped with the fix
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",
Loading diff…

Original Bug Report

reported by [email protected]

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.cc
  • third_party/blink/renderer/core/page/create_window.cc
  • content/renderer/render_frame_impl.cc
  • content/browser/renderer_host/ipc_utils.cc
  • components/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:

  1. Feature Parsing: In third_party/blink/renderer/core/page/create_window.cc around line 210, the renderer unconditionally parses the 'background' keyword and sets window_features.background = true.
  2. Parameters Mapping: In content/renderer/render_frame_impl.cc:6862, WindowFeaturesToContainerType maps this feature to content::mojom::WindowContainerType::BACKGROUND inside params->window_container_type.
  3. IPC Transfer: The renderer sends these parameters via the synchronous CreateNewWindow IPC interface to the browser process (content/browser/renderer_host/render_frame_host_impl.cc:10274).
  4. Browser Policy Evaluation: The browser process delegates the request validation to the content embedder’s CanCreateWindow interface. In chrome/browser/chrome_content_browser_client.cc around lines 4529–4553:
    if (container_type == content::mojom::WindowContainerType::BACKGROUND) {
    #if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
        // Extension-specific background permission checks
        ...
    #endif
        return true;
    }
    
    Because Chrome for Android compiles without extension support (ENABLE_EXTENSIONS_CORE is false), the compiler strips the permission check inside the #if block. This results in an unconditional early return true; for any page requesting a BACKGROUND container type.
  5. Blocker Bypass: Due to this early return, the execution path never reaches the end of the CanCreateWindow function where ConsiderForPopupBlocking and MaybeBlockPopup are 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.

We suggest the following structural changes to resolve this potential issue:

  1. Move the return true; statement at chrome/browser/chrome_content_browser_client.cc:4552 inside the #if BUILDFLAG(ENABLE_EXTENSIONS_CORE) block. In environments without extensions support, the handler should fall through to standard popup blocking validation.
  2. In content/browser/renderer_host/ipc_utils.cc:VerifyCreateNewWindowParams, add defense-in-depth checks to validate and reject requests specifying WindowContainerType::BACKGROUND or PERSISTENT from 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.

View on issue tracker