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 <dsv@chromium.org>
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 <finnur@chromium.org>
Auto-Submit: Danil Somsikov <dsv@chromium.org>
Reviewed-by: Alex Rudenko <alexrudenko@chromium.org>
Commit-Queue: Danil Somsikov <dsv@chromium.org>
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 al...@gmail.com
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