Chrome · BrowserTag
CVE-2026-113269
Memory Corruption in BrowserTag
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
forchrome/test/data/webui/webview/webui_webview_browsertest.cc |
modified | |
suitechrome/test/data/webui/webview/webview_untrusted_test.ts |
modified |
Files Changed
extensions/browser/guest_view/web_view/web_view_permission_helper.ccchrome/test/data/webui/webview/webview_untrusted_test.tschrome/test/data/webui/webview/webui_webview_browsertest.cc
Patch
From 8d17e06dbdfe0a7c0e8042a78ee0328c1f55cc46 Mon Sep 17 00:00:00 2001 From: Kevin McNee <[email protected]> Date: Tue, 22 Sep 2026 15:17:50 -0700 Subject: [PATCH] Prevent chrome-untrusted from approving webview permissions Similar to https://crbug.com/502179319 if a webview has a chrome-untrusted page as an embedder, it should not be trusted to grant permissions. Fixed: 553334273 Change-Id: Ic1461da87e31c75786c8742a45e45bf07079e4ac Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8431428 Reviewed-by: Alex Moshchuk <[email protected]> Auto-Submit: Kevin McNee <[email protected]> Commit-Queue: Kevin McNee <[email protected]> Cr-Commit-Position: refs/heads/main@{#1702992} --- diff --git a/extensions/browser/guest_view/web_view/web_view_permission_helper.cc b/extensions/browser/guest_view/web_view/web_view_permission_helper.cc index 693c97f..d3bfc80e 100644 --- a/extensions/browser/guest_view/web_view/web_view_permission_helper.cc +++ b/extensions/browser/guest_view/web_view/web_view_permission_helper.cc @@ -440,6 +440,19 @@ return; } + // A chrome-untrusted embedder can't be trusted to approve permissions. + // New Window and Dialog are excluded, since they reuse this path but aren't + // really permissions. + if (permission_type != WEB_VIEW_PERMISSION_TYPE_NEW_WINDOW && + permission_type != WEB_VIEW_PERMISSION_TYPE_JAVASCRIPT_DIALOG && + web_view_guest_->GetOwnerSiteURL().SchemeIs( + content::kChromeUIUntrustedScheme)) { + base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, + base::BindOnce(std::move(callback), allowed_by_default, std::string())); + return; + } + int request_id = next_permission_request_id_++; pending_permission_requests_[request_id] = PermissionResponseInfo( std::move(callback), permission_type, allowed_by_default); diff --git a/chrome/test/data/webui/webview/webui_webview_browsertest.cc b/chrome/test/data/webui/webview/webui_webview_browsertest.cc index c128fd95..0993a424 100644 --- a/chrome/test/data/webui/webview/webui_webview_browsertest.cc +++ b/chrome/test/data/webui/webview/webui_webview_browsertest.cc @@ -30,10 +30,12 @@ #include "chrome/test/base/test_switches.h" #include "chrome/test/base/ui_test_utils.h" #include "chrome/test/base/web_ui_mocha_browser_test.h" +#include "components/download/public/common/download_item.h" #include "components/prefs/pref_service.h" #include "components/webui/chrome_urls/pref_names.h" #include "content/public/browser/back_forward_cache.h" #include "content/public/browser/context_menu_params.h" +#include "content/public/browser/download_manager.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host.h" #include "content/public/browser/web_contents.h" @@ -551,6 +553,10 @@ WebUIMochaBrowserTest::SetUpOnMainThread(); } + GURL GetTestUrl(const std::string& path) const { + return embedded_test_server()->base_url().Resolve(path); + } + content::WebContents* GetWebContentsForTesting() { return browser()->tab_strip_model()->GetActiveWebContents(); } @@ -568,4 +574,25 @@ true)); } +IN_PROC_BROWSER_TEST_F(UntrustedWebUIWebViewBrowserTest, + PermissionRequestAutoDeny) { + EXPECT_TRUE(RunTestOnWebContents( + GetWebContentsForTesting(), "webview/webview_untrusted_test.js", + base::StringPrintf("window.downloadUrl = '%s'; " + "runMochaTest('WebviewUntrustedBasicTest', " + "'PermissionRequestAutoDenyInUntrusted');", + GetTestUrl("download-test3.gif").spec().c_str()), + true)); + + content::DownloadManager::DownloadVector downloads; + browser()->GetProfile()->GetDownloadManager()->GetAllDownloads(&downloads); + EXPECT_TRUE(downloads.empty()); + // If the test fails and a download was started, cancel it so that an + // in-progress download prompt does not block browser shutdown during test + // teardown. + for (download::DownloadItem* download : downloads) { + download->Cancel(false); + } +} + #endif // !BUILDFLAG(IS_MAC) diff --git a/chrome/test/data/webui/webview/webview_untrusted_test.ts b/chrome/test/data/webui/webview/webview_untrusted_test.ts index 2c504f66..2ce33ef 100644 --- a/chrome/test/data/webui/webview/webview_untrusted_test.ts +++ b/chrome/test/data/webui/webview/webview_untrusted_test.ts @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {assertThrows} from 'chrome-untrusted://webui-test/chai_assert.js'; +import {assertFalse, assertThrows} from 'chrome-untrusted://webui-test/chai_assert.js'; suite('WebviewUntrustedBasicTest', function() { function createWebview(): chrome.webviewTag.WebView { @@ -12,6 +12,10 @@ return webview; } + function getDownloadUrl(): string { + return (window as unknown as Window & {downloadUrl: string}).downloadUrl; + } + test('BannedApisThrowInUntrusted', async () => { const webview = createWebview(); await new Promise(resolve => { @@ -37,4 +41,21 @@ webview.loadDataWithBaseUrl('data:text/html,test', 'https://example.com'); }); }); + + test('PermissionRequestAutoDenyInUntrusted', async () => { + const webview = createWebview(); + let receivedPermissionRequest = false; + webview.addEventListener('permissionrequest', event => { + receivedPermissionRequest = true; + const e = event as chrome.webviewTag.PermissionRequestEvent; + e.request.allow(); + }); + + await new Promise(resolve => { + webview.src = getDownloadUrl(); + webview.addEventListener('loadstop', resolve); + }); + + assertFalse(receivedPermissionRequest); + }); });
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/chrome/test/data/webui/webview/webui_webview_browsertest.cc b/chrome/test/data/webui/webview/webui_webview_browsertest.cc
index c128fd95..0993a424 100644
--- a/chrome/test/data/webui/webview/webui_webview_browsertest.cc
+++ b/chrome/test/data/webui/webview/webui_webview_browsertest.cc
@@ -30,10 +30,12 @@
#include "chrome/test/base/test_switches.h"
#include "chrome/test/base/ui_test_utils.h"
#include "chrome/test/base/web_ui_mocha_browser_test.h"
+#include "components/download/public/common/download_item.h"
#include "components/prefs/pref_service.h"
#include "components/webui/chrome_urls/pref_names.h"
#include "content/public/browser/back_forward_cache.h"
#include "content/public/browser/context_menu_params.h"
+#include "content/public/browser/download_manager.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/web_contents.h"
@@ -551,6 +553,10 @@
WebUIMochaBrowserTest::SetUpOnMainThread();
}
+ GURL GetTestUrl(const std::string& path) const {
+ return embedded_test_server()->base_url().Resolve(path);
+ }
+
content::WebContents* GetWebContentsForTesting() {
return browser()->tab_strip_model()->GetActiveWebContents();
}
@@ -568,4 +574,25 @@
true));
}
+IN_PROC_BROWSER_TEST_F(UntrustedWebUIWebViewBrowserTest,
+ PermissionRequestAutoDeny) {
+ EXPECT_TRUE(RunTestOnWebContents(
+ GetWebContentsForTesting(), "webview/webview_untrusted_test.js",
+ base::StringPrintf("window.downloadUrl = '%s'; "
+ "runMochaTest('WebviewUntrustedBasicTest', "
+ "'PermissionRequestAutoDenyInUntrusted');",
+ GetTestUrl("download-test3.gif").spec().c_str()),
+ true));
+
+ content::DownloadManager::DownloadVector downloads;
+ browser()->GetProfile()->GetDownloadManager()->GetAllDownloads(&downloads);
+ EXPECT_TRUE(downloads.empty());
+ // If the test fails and a download was started, cancel it so that an
+ // in-progress download prompt does not block browser shutdown during test
+ // teardown.
+ for (download::DownloadItem* download : downloads) {
+ download->Cancel(false);
+ }
+}
+
#endif // !BUILDFLAG(IS_MAC)
diff --git a/chrome/test/data/webui/webview/webview_untrusted_test.ts b/chrome/test/data/webui/webview/webview_untrusted_test.ts
index 2c504f66..2ce33ef 100644
--- a/chrome/test/data/webui/webview/webview_untrusted_test.ts
+++ b/chrome/test/data/webui/webview/webview_untrusted_test.ts
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import {assertThrows} from 'chrome-untrusted://webui-test/chai_assert.js';
+import {assertFalse, assertThrows} from 'chrome-untrusted://webui-test/chai_assert.js';
suite('WebviewUntrustedBasicTest', function() {
function createWebview(): chrome.webviewTag.WebView {
@@ -12,6 +12,10 @@
return webview;
}
+ function getDownloadUrl(): string {
+ return (window as unknown as Window & {downloadUrl: string}).downloadUrl;
+ }
+
test('BannedApisThrowInUntrusted', async () => {
const webview = createWebview();
await new Promise(resolve => {
@@ -37,4 +41,21 @@
webview.loadDataWithBaseUrl('data:text/html,test', 'https://example.com');
});
});
+
+ test('PermissionRequestAutoDenyInUntrusted', async () => {
+ const webview = createWebview();
+ let receivedPermissionRequest = false;
+ webview.addEventListener('permissionrequest', event => {
+ receivedPermissionRequest = true;
+ const e = event as chrome.webviewTag.PermissionRequestEvent;
+ e.request.allow();
+ });
+
+ await new Promise(resolve => {
+ webview.src = getDownloadUrl();
+ webview.addEventListener('loadstop', resolve);
+ });
+
+ assertFalse(receivedPermissionRequest);
+ });
});
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