Chrome · DevTools
CVE-2026-11189
Logic Error in DevTools
Overview
Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifchrome/browser/devtools/protocol/target_handler_android.cc |
modified | |
IN_PROC_BROWSER_TEST_Fchrome/browser/extensions/api/debugger/debugger_apitest.cc |
modified |
Files Changed
chrome/browser/devtools/protocol/target_handler_android.ccchrome/browser/devtools/protocol/target_handler_android.hchrome/browser/extensions/api/debugger/debugger_apitest.cccontent/browser/devtools/render_frame_devtools_agent_host.cc
Patch
From 8bd52544c5cfb9b1108cc9235dc24885e2525aa5 Mon Sep 17 00:00:00 2001 From: Danil Somsikov <[email protected]> Date: Tue, 19 May 2026 09:54:00 -0700 Subject: [PATCH] [DevTools] Add missing trust checks in TargetHandlerAndroid::CreateTarget Untrusted DevTools clients were able to bypass restrictions and open arbitrary `devtools://`, `chrome-untrusted://` URLs by using the Target.createTarget CDP command on Android. The desktop implementation (TargetHandler::CreateTarget) was previously patched for this issue (crbug.com/503197481), but the Android port accepted the `is_trusted` and `may_read_local_files` parameters in its constructor without ever storing or evaluating them. This CL fixes the vulnerability by: 1. Storing `is_trusted` and `may_read_local_files` as member variables in `TargetHandlerAndroid`. 2. Adding URL scheme validation in `TargetHandlerAndroid::CreateTarget` to reject privileged schemes from untrusted clients and block creation of targets with local files when not permitted, matching the desktop behavior. 3. Enabling the `CreateTargetToUntrustedWebUI` test for Android in `debugger_apitest.cc` to ensure ongoing coverage. Bug: 512249559 Change-Id: I304e44a5585288f81197252b090bb4d6dab0b1a1 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7857154 Reviewed-by: Finnur Thorarinsson <[email protected]> Auto-Submit: Danil Somsikov <[email protected]> Reviewed-by: Alex Rudenko <[email protected]> Commit-Queue: Danil Somsikov <[email protected]> Cr-Commit-Position: refs/heads/main@{#1632957} --- diff --git a/chrome/browser/devtools/protocol/target_handler_android.cc b/chrome/browser/devtools/protocol/target_handler_android.cc index 578fe99e..70ffafbc 100644 --- a/chrome/browser/devtools/protocol/target_handler_android.cc +++ b/chrome/browser/devtools/protocol/target_handler_android.cc @@ -8,12 +8,16 @@ #include "chrome/browser/ui/android/tab_model/tab_model.h" #include "chrome/browser/ui/android/tab_model/tab_model_list.h" #include "content/public/browser/web_contents.h" +#include "content/public/common/url_constants.h" +#include "content/public/common/url_utils.h" +#include "url/url_constants.h" using content::WebContents; TargetHandlerAndroid::TargetHandlerAndroid(protocol::UberDispatcher* dispatcher, bool is_trusted, - bool may_read_local_files) { + bool may_read_local_files) + : is_trusted_(is_trusted), may_read_local_files_(may_read_local_files) { protocol::Target::Dispatcher::wire(dispatcher, this); } @@ -58,8 +62,29 @@ TabModel* tab_model = models[0]; CHECK(tab_model); + GURL gurl(url); + if (gurl.is_empty()) { + gurl = GURL(url::kAboutBlankURL); + } + + GURL inner_url = gurl; + if (gurl.SchemeIs(content::kViewSourceScheme)) { + inner_url = GURL(gurl.GetContent()); + } + + if (!is_trusted_ && (inner_url.SchemeIs(content::kChromeUIUntrustedScheme) || + inner_url.SchemeIs(content::kChromeDevToolsScheme))) { + return protocol::Response::ServerError( + "Navigating to a URL with a privileged scheme is not allowed"); + } + + if (!may_read_local_files_ && inner_url.SchemeIsFile()) { + return protocol::Response::ServerError( + "Creating a target with a local URL is not allowed"); + } + WebContents* web_contents = - tab_model->CreateNewTabForDevTools(GURL(url), new_window.value_or(false)); + tab_model->CreateNewTabForDevTools(gurl, new_window.value_or(false)); if (!web_contents) { return protocol::Response::ServerError("Could not create a Tab"); } diff --git a/chrome/browser/devtools/protocol/target_handler_android.h b/chrome/browser/devtools/protocol/target_handler_android.h index ba693fab6..c092c1d 100644 --- a/chrome/browser/devtools/protocol/target_handler_android.h +++ b/chrome/browser/devtools/protocol/target_handler_android.h @@ -46,6 +46,8 @@ std::string* out_target_id) override; private: + bool is_trusted_ = false; + bool may_read_local_files_ = false; RemoteLocations remote_locations_; }; diff --git a/chrome/browser/extensions/api/debugger/debugger_apitest.cc b/chrome/browser/extensions/api/debugger/debugger_apitest.cc index 4570311..934b79e 100644 --- a/chrome/browser/extensions/api/debugger/debugger_apitest.cc +++ b/chrome/browser/extensions/api/debugger/debugger_apitest.cc @@ -1150,7 +1150,6 @@ } #if BUILDFLAG(ENABLE_EXTENSIONS) -// TODO(crbug.com/441339825): Fails on desktop Android. // Tests that Target.createTarget to WebUI origins are blocked. IN_PROC_BROWSER_TEST_F(DebuggerExtensionApiTest, CreateTargetToUntrustedWebUI) { ASSERT_TRUE(RunExtensionTest("debugger_create_target_to_untrusted_webui")) diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc index b55c73d0..c6cd2b7 100644 --- a/content/browser/devtools/render_frame_devtools_agent_host.cc +++ b/content/browser/devtools/render_frame_devtools_agent_host.cc @@ -579,8 +579,9 @@ RenderFrameHostImpl* old_host = frame_host_; ChangeFrameHostAndObservedProcess(frame_host); - if (IsAttached()) + if (IsAttached()) { UpdateRawHeadersAccess(old_host, nullptr); + } UpdateFrameAlive(); }
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/chrome/browser/extensions/api/debugger/debugger_apitest.cc b/chrome/browser/extensions/api/debugger/debugger_apitest.cc
index 4570311..934b79e 100644
--- a/chrome/browser/extensions/api/debugger/debugger_apitest.cc
+++ b/chrome/browser/extensions/api/debugger/debugger_apitest.cc
@@ -1150,7 +1150,6 @@
}
#if BUILDFLAG(ENABLE_EXTENSIONS)
-// TODO(crbug.com/441339825): Fails on desktop Android.
// Tests that Target.createTarget to WebUI origins are blocked.
IN_PROC_BROWSER_TEST_F(DebuggerExtensionApiTest, CreateTargetToUntrustedWebUI) {
ASSERT_TRUE(RunExtensionTest("debugger_create_target_to_untrusted_webui"))
Loading diff…
Original Bug Report
reported by [email protected]
Incomplete patch for Issue 439058242: Untrusted DevTools clients can still navigate window to arbitrary `devtools://` URLs
redacted
View on issue tracker
References
On This Page