Medium chrome Logic Error 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInsufficient validation of untrusted input in DevTools
DescriptionInsufficient validation of untrusted input in DevTools
ComponentDevTools
Bug ClassLogic Error
Tracker503197481
Fix commit8bd52544c5cf (chromium/src) +31/-4
CISA KEVNot listed
Creditedlebr0nli of National Yang Ming Chiao Tung University, Dept. of CS, Security and Systems Lab
Disclosed2026-06-02

Changed Functions

FunctionChangeNotes
if
chrome/browser/devtools/protocol/target_handler_android.cc
modified
IN_PROC_BROWSER_TEST_F
chrome/browser/extensions/api/debugger/debugger_apitest.cc
modified

Files Changed

  • chrome/browser/devtools/protocol/target_handler_android.cc
  • chrome/browser/devtools/protocol/target_handler_android.h
  • chrome/browser/extensions/api/debugger/debugger_apitest.cc
  • content/browser/devtools/render_frame_devtools_agent_host.cc
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