Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInsufficient policy enforcement in WebView tag
DescriptionInsufficient policy enforcement in WebView tag
ComponentWebView tag
Bug ClassLogic Error
Tracker463155954
Fix commit28628907f24e (chromium/src) +71/-0
CISA KEVNot listed
CreditedGal Weizman
Disclosed2026-01-06

Changed Functions

FunctionChangeNotes
if
extensions/browser/api/declarative_net_request/ruleset_manager.cc
modified

Files Changed

  • chrome/browser/apps/guest_view/web_view_browsertest.cc
  • chrome/test/data/extensions/api_test/declarative_net_request/block_chrome_signin/manifest.json
  • chrome/test/data/extensions/api_test/declarative_net_request/block_chrome_signin/rules.json
  • extensions/browser/api/declarative_net_request/ruleset_manager.cc
From 28628907f24e27fff20d26471482f377047db3c8 Mon Sep 17 00:00:00 2001
From: Kelvin Jiang <[email protected]>
Date: Tue, 30 Dec 2025 11:22:24 -0800
Subject: [PATCH] [Extensions] Do not apply DNR rules for Webview requests

Extensions should not be able to apply DNR rules to requests originating
from WebViews.

Bug: 463155954
Change-Id: I50bcf9d32480407cfa76bb0bfe6cab67351c43ec
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7354432
Reviewed-by: Devlin Cronin <[email protected]>
Commit-Queue: Kelvin Jiang <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1563452}
---

diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index 79748346..f2b0c78 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -130,6 +130,8 @@
 #include "extensions/browser/api/declarative/rules_registry.h"
 #include "extensions/browser/api/declarative/rules_registry_service.h"
 #include "extensions/browser/api/declarative/test_rules_registry.h"
+#include "extensions/browser/api/declarative_net_request/action_tracker.h"
+#include "extensions/browser/api/declarative_net_request/rules_monitor_service.h"
 #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h"
 #include "extensions/browser/api/extensions_api_client.h"
 #include "extensions/browser/app_window/native_app_window.h"
@@ -5801,6 +5803,40 @@
                          testing::Bool(),
                          ChromeSignInWebViewTest::DescribeParams);
 
+// Check that rules from the DeclarativeNetRequest API are not matched for
+// requests originating from WebViews.
+IN_PROC_BROWSER_TEST_P(ChromeSignInWebViewTest,
+                       DeclarativeNetRequestRulesNotMatched) {
+  SKIP_FOR_MPARCH();  // TODO(crbug.com/40202416): Enable test for MPArch.
+
+  // Load an extension that blocks all main frame requests into
+  // accounts.google.com which is loaded inside the WebView in
+  // chrome://chrome-signin.
+  const auto* extension = LoadExtension(test_data_dir_.AppendASCII(
+      "api_test/declarative_net_request/block_chrome_signin"));
+
+  // Navigate to a WebUI page that contains a WebView which loads
+  // accounts.google.com.
+  const GURL signin_url{"chrome://chrome-signin/?reason=6"};
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), signin_url));
+  WaitForWebViewInDom();
+
+  // Check that no rules were matched from the extension. Note that the test
+  // would not complete if the accounts.google.com request from the WebView is
+  // blocked.
+  extensions::declarative_net_request::RulesMonitorService*
+      rules_monitor_service =
+          extensions::declarative_net_request::RulesMonitorService::Get(
+              browser()->profile());
+  ASSERT_TRUE(rules_monitor_service);
+  extensions::declarative_net_request::ActionTracker& action_tracker =
+      rules_monitor_service->action_tracker();
+
+  EXPECT_TRUE(action_tracker
+                  .GetMatchedRules(*extension, std::nullopt, base::Time::Min())
+                  .empty());
+}
+
 // This verifies the fix for http://crbug.com/667708.
 IN_PROC_BROWSER_TEST_P(ChromeSignInWebViewTest,
                        ClosingChromeSignInShouldNotCrash) {
diff --git a/chrome/test/data/extensions/api_test/declarative_net_request/block_chrome_signin/manifest.json b/chrome/test/data/extensions/api_test/declarative_net_request/block_chrome_signin/manifest.json
new file mode 100644
index 0000000..86a7614
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/declarative_net_request/block_chrome_signin/manifest.json
@@ -0,0 +1,16 @@
+{
+  "name": "Block Chrome signin page extension",
+  "declarative_net_request": {
+    "rule_resources": [{
+      "id": "1",
+      "path": "rules.json",
+      "enabled": true
+    }]
+  },
+  "manifest_version": 3,
+  "permissions": [
+    "declarativeNetRequest",
+    "declarativeNetRequestFeedback"
+  ],
+  "version": "1.0"
+}
diff --git a/chrome/test/data/extensions/api_test/declarative_net_request/block_chrome_signin/rules.json b/chrome/test/data/extensions/api_test/declarative_net_request/block_chrome_signin/rules.json
new file mode 100644
index 0000000..7416518
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/declarative_net_request/block_chrome_signin/rules.json
@@ -0,0 +1,13 @@
+[
+  {
+    "id": 1,
+    "priority": 999,
+    "action": {
+      "type": "block"
+    },
+    "condition": {
+      "urlFilter": "accounts.google.com",
+      "resourceTypes" : ["main_frame"]
+    }
+  }
+]
diff --git a/extensions/browser/api/declarative_net_request/ruleset_manager.cc b/extensions/browser/api/declarative_net_request/ruleset_manager.cc
index 2b36ce05..4dadc8d 100644
--- a/extensions/browser/api/declarative_net_request/ruleset_manager.cc
+++ b/extensions/browser/api/declarative_net_request/ruleset_manager.cc
@@ -521,6 +521,12 @@
     return false;
   }
 
+  // Declarative Net Request rules should not be matched against requests
+  // originating from WebViews.
+  if (request.is_web_view) {
+    return false;
+  }
+
   return true;
 }
 
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index 79748346..f2b0c78 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -130,6 +130,8 @@
 #include "extensions/browser/api/declarative/rules_registry.h"
 #include "extensions/browser/api/declarative/rules_registry_service.h"
 #include "extensions/browser/api/declarative/test_rules_registry.h"
+#include "extensions/browser/api/declarative_net_request/action_tracker.h"
+#include "extensions/browser/api/declarative_net_request/rules_monitor_service.h"
 #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h"
 #include "extensions/browser/api/extensions_api_client.h"
 #include "extensions/browser/app_window/native_app_window.h"
@@ -5801,6 +5803,40 @@
                          testing::Bool(),
                          ChromeSignInWebViewTest::DescribeParams);
 
+// Check that rules from the DeclarativeNetRequest API are not matched for
+// requests originating from WebViews.
+IN_PROC_BROWSER_TEST_P(ChromeSignInWebViewTest,
+                       DeclarativeNetRequestRulesNotMatched) {
+  SKIP_FOR_MPARCH();  // TODO(crbug.com/40202416): Enable test for MPArch.
+
+  // Load an extension that blocks all main frame requests into
+  // accounts.google.com which is loaded inside the WebView in
+  // chrome://chrome-signin.
+  const auto* extension = LoadExtension(test_data_dir_.AppendASCII(
+      "api_test/declarative_net_request/block_chrome_signin"));
+
+  // Navigate to a WebUI page that contains a WebView which loads
+  // accounts.google.com.
+  const GURL signin_url{"chrome://chrome-signin/?reason=6"};
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), signin_url));
+  WaitForWebViewInDom();
+
+  // Check that no rules were matched from the extension. Note that the test
+  // would not complete if the accounts.google.com request from the WebView is
+  // blocked.
+  extensions::declarative_net_request::RulesMonitorService*
+      rules_monitor_service =
+          extensions::declarative_net_request::RulesMonitorService::Get(
+              browser()->profile());
+  ASSERT_TRUE(rules_monitor_service);
+  extensions::declarative_net_request::ActionTracker& action_tracker =
+      rules_monitor_service->action_tracker();
+
+  EXPECT_TRUE(action_tracker
+                  .GetMatchedRules(*extension, std::nullopt, base::Time::Min())
+                  .empty());
+}
+
 // This verifies the fix for http://crbug.com/667708.
 IN_PROC_BROWSER_TEST_P(ChromeSignInWebViewTest,
                        ClosingChromeSignInShouldNotCrash) {
diff --git a/chrome/test/data/extensions/api_test/declarative_net_request/block_chrome_signin/manifest.json b/chrome/test/data/extensions/api_test/declarative_net_request/block_chrome_signin/manifest.json
new file mode 100644
index 0000000..86a7614
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/declarative_net_request/block_chrome_signin/manifest.json
@@ -0,0 +1,16 @@
+{
+  "name": "Block Chrome signin page extension",
+  "declarative_net_request": {
+    "rule_resources": [{
+      "id": "1",
+      "path": "rules.json",
+      "enabled": true
+    }]
+  },
+  "manifest_version": 3,
+  "permissions": [
+    "declarativeNetRequest",
+    "declarativeNetRequestFeedback"
+  ],
+  "version": "1.0"
+}
diff --git a/chrome/test/data/extensions/api_test/declarative_net_request/block_chrome_signin/rules.json b/chrome/test/data/extensions/api_test/declarative_net_request/block_chrome_signin/rules.json
new file mode 100644
index 0000000..7416518
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/declarative_net_request/block_chrome_signin/rules.json
@@ -0,0 +1,13 @@
+[
+  {
+    "id": 1,
+    "priority": 999,
+    "action": {
+      "type": "block"
+    },
+    "condition": {
+      "urlFilter": "accounts.google.com",
+      "resourceTypes" : ["main_frame"]
+    }
+  }
+]
Loading diff…

Original Bug Report

reported by [email protected]

Extensions can hijack Gemini in the browser webview process to perform PE attacks by abusing DNR permissions, allowing stealing prompts, PII leakage, unrestricted access to camera-microphone and more


Report description

Extensions can hijack Gemini in the browser webview process to perform PE attacks by abusing DNR permissions, allowing stealing prompts, PII leakage, unrestricted access to camera-microphone and more


Bug location

Where do you want to report your vulnerability?

Chrome VRP – Report security issues affecting the Chrome browser. See program rules

Which URL (or repository) have you found the vulnerability in?

Gemini (webview) in the browser


The problem

Please describe the technical details of the vulnerability

(DEMO VID - https://drive.google.com/file/d/1rA5FdPQwvEtuskNB_qaGXIXdXksAYjma/view?usp=sharing)

New Gemini in the browser feature in Chrome allows users to activate a new window that renders a special component of a Gemini instance that combines capabilities of generating remote Gemini AI responses and manipulating the browser based on them.

This new component is very clearly a browser-level entity, baked into the browser, aiming to be a builtin enhancement of it, thus superior to websites and installed extensions.

This is clearly proven by Chrome’s implemented enforcement around this new component, where affecting it from outside isn’t allowed and explicitly blocked. For example, executing content-scripts or attaching debugger capabilities against the special component fail to take place completely.

What’s further clear is that this isn’t an origin-level decision, but a process decision, because injecting content-scripts to gemini.google.com via extensions is allowed if loaded as an ordinary website, but not when attempted against the new special component.

This expresses how Gemini in the browser is a feature that serves the browser itself and therefore must remain superior to inferior entities such as websites an extensions.

Unfortunately, it seems that DeclarativeNetRequests (DNR) permissions were not taken into account, with which a malicious extension can inject code directly under gemini.google.com within the special webview component of Gemini in the browser, thus allowing to undermine and hijack it completely.

All an attacker has to do is to use DNR to remove protecting headers (e.g. CSP, DiP, CORP, etc) and then redirect one script served by the Gemini app with an attacker controlled script.

To be more specific, here are the challenges required to tackle in order to perform the attack successfully:

  1. First, find a script that is not necessary for the Gemini web app so we can replace it with our own. For that I picked https://www.gstatic.com/feedback/js/help/prod/service/lazy.min.js and used DNR to redirect it to https://weizmangal.com/public/try.js which is a JS I control
  2. CSP won’t allow it, therefore we craft a DNR rule to drop CSP of gemini.google.com all together
  3. Within the webview context, the Gemini app counts on SAB which requires a document-isolation-policy. This is a problem because that same policy rejects my script coming from a cross-origin, so I simply replace its value to isolate-and-credentialless so that SAB works but pulling cross-origin scripts works too
  4. Next, since DNR works with https: URLs, I had to pull my malicious code from the web, but I didn’t want people to see what I’m up to online and also I needed a faster way to work than deploy scripts online every few seconds. Therefore, I implemented a mechanizm that implements the attack in B64 and sets it to the DNR URL as a query param, pointing at a constant online script that takes the B64 from the query param and executes it (this is essentially the only visible difference between each of the attached rules.json files).

Impact analysis – Please briefly explain who can exploit the vulnerability, and what they gain when doing so

(DEMO VID - https://drive.google.com/file/d/1rA5FdPQwvEtuskNB_qaGXIXdXksAYjma/view?usp=sharing)

Anyone with access to installed extensions with common DNR permissions can perform this attack, whether by tricking users into installing malicious extensions or by infecting already legit extensions into doing this (e.g. AdBlock already has necessary permissions to perform such an attack). For starters, rules.json shows how we manage to run a simple console.log under gemini.google.com within the webview.

The impact that can be achieved is as wide as the range of capabilities the Gemini in the browser process is exposed to, for example:

  1. An attacker can intercept requests and responses within the app to steal/fabricate prompt communication with Gemini (rules_intercept.json)
  2. An attacker can phish the user into interacting with fake layout to be tricked into providing sensitive information (rules_phish.json)
  3. An attacker can ride on the already established communication channel with the host of the webview (chrome://glic) and intercept post messages to either steal sensitive information or force the browser to perform sensitive actions (rules_leak_pii.json)
  4. An attacker can escalate its privileges and access capabilities it does not hold from the stance of an extension, such as camera and microphone (rules_pe.json)

All of those will be demonstrated in the attached PoC.

At first glance it might seem that most of this impact can be trivially achieved once an extension has access to DNR permissions. For example, intercepting Gemini requests and/or drawing fraudulent phishing layout can be done against the web app just as well. However, this is fundamentally different for the following reason:

As opposed to the Gemini web app, to which an extension is naturally superior, the Gemini in the browser webview is served as part of the browser, which sends a message to the user that says “this is a highly trusted component, not like websites”. Given that, undermining it is more impactful. A proof of that is how the Gemini web app is allowed to be injected with content-scripts, but when loaded within the webview, isn’t.

Not only the component can be attacked when looked at as the ordinary Gemini web app, but within this special context, new attack surface becomes available. I was able to ride on the established communication with the embedder of the webview and intercept exchanged messages between them. For example, I’ve learned how message glicBrowserGetUserProfileInfo leaks the name and gmail account that is logged into the browser on the profile level, which is not trivially accessible to extensions. Furthermore, I was able to make the host perform any operation it is designed to support coming from the app, such as opening new tabs, resizing the webview window and more.

This discovery arrives just in time, right before glicBrowserCreateTask, glicBrowserPerformActions, glicBrowserJournalSnapshot and more are fully utilized, allowing attackers to perform far more damage by learning what Gemini actors do and perhaps instruct them maliciously.

On top of that, since the process is endowed with special capabilities such as access to camera or microphone (after user settings activation), malicious code running within this process can access those without prompting the user for permission, unlike how site permissions usually work. This effectively allows an attacker coming from an extension without such power, to ride the Gemini in browser webview and access such devices without any need for user interaction (except for starting Gemini) - aka, a classic escalation of privileges attack.


The cause

What version of Chrome have you found the security issue in?

142.0.7444.176 stable

No, it is not related to a crash.

Choose the type of vulnerability

Privilege Escalation

How would you like to be publicly acknowledged for your report?

Gal Weizman

View on issue tracker