CVE-2025-0443
Overview
Background
- DevTools Extension API
- the
ExtensionAPI.tssurface that DevTools exposes to third-party extensions, gating access to page resources through checks likecanAccessResource. - Prototype pollution
- an attack where a script mutates a shared prototype object (e.g.
URL.prototype) so that later property lookups return attacker-controlled values instead of the built-in ones. - `canAccessResource`
- the guard function that decides whether an extension may read a given resource, permitting it unless the resource’s
protocolisfile:and file access is disallowed. - `URL.prototype.protocol`
- a built-in accessor whose getter normally returns a URL’s scheme, but which can be redefined on the shared prototype at runtime.
Root Cause Analysis
The vulnerable path is canAccessResource, which computed a resource’s scheme with (new URL(resource.url)).protocol and allowed access whenever that value was not the literal string file:. Because .protocol is resolved dynamically through the URL.prototype.protocol accessor, an attacker running in the same realm could redefine that getter (prototype pollution) so it returns something other than file: even for a file:-scheme resource, defeating the intended check. The invariant violated is that the security decision must reflect the resource’s true scheme rather than a caller-influenceable property lookup.
The fix captures the genuine getter once at module load via Object.getOwnPropertyDescriptor(URL.prototype, 'protocol')?.get and invokes it directly through a helper getProtocol, so a later mutation of URL.prototype.protocol no longer affects the comparison. This restores the guarantee that the file: comparison is made against the real, unspoofable protocol value.
protocol) through the live prototype chain, which an attacker can pollute; the fix pins the original accessor getter at load time and calls it directly, so the check can no longer be subverted.Attack Path
- Redefine the accessor
Attacker-controlled code in the DevTools/extension realm overrides
URL.prototype.protocol(or its getter) so that it no longer reports the true scheme. - Reference a file resource
The attacker triggers an extension API call referencing a resource whose real scheme is
file:, which should be blocked when file access is not granted. - Bypass the guard
Inside
canAccessResource,(new URL(resource.url)).protocolnow returns the polluted value, so the!== 'file:'comparison evaluates true. - Gain access
The function returns
true, granting the extension read access to thefile:-scheme resource it should have been denied.
Impact Assessment
URL.prototype.protocol to bypass the file: scheme restriction and read local file resources that allowFileAccess was meant to protect. This requires the ability to execute code in that realm and a resource resolving to a file: URL, and the gain is unauthorized local resource disclosure through the DevTools extension API rather than remote code execution.Changed Functions
| Function | Change | Notes |
|---|---|---|
iffront_end/models/extensions/ExtensionAPI.ts |
modified |
Files Changed
front_end/models/extensions/ExtensionAPI.ts
Audit Directions
- Live property reads in security checksLook for guards that resolve DOM/JS built-in properties (
protocol,hostname,origin, array/object methods) through the prototype chain when making trust decisions, as these are pollutable. - Unpinned built-in accessorsAudit code paths that rely on
URL,Array,Object, or other intrinsics without capturing their descriptors at load time, especially where extension or page script shares the realm. - String-comparison authorizationReview any allow/deny logic that compares a dynamically derived string (scheme, extension, MIME) against a constant, since the derivation source may be attacker-influenced.
Patch
From b50c1dbc6b709196064bb26ee75b1ed6cee4f974 Mon Sep 17 00:00:00 2001
From: Danil Somsikov <dsv@chromium.org>
Date: Mon, 04 Nov 2024 12:09:10 +0000
Subject: [PATCH] Protect canAccessResource in DevTools API form prototype pollution
Bug: 376625003
Change-Id: Ib07a65da8f342c4727bceb6afcbd920bcfd07b81
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/5987430
Reviewed-by: Philip Pfaffe <pfaffe@chromium.org>
Commit-Queue: Danil Somsikov <dsv@chromium.org>
---
diff --git a/front_end/models/extensions/ExtensionAPI.ts b/front_end/models/extensions/ExtensionAPI.ts
index 54afa52..a346408 100644
--- a/front_end/models/extensions/ExtensionAPI.ts
+++ b/front_end/models/extensions/ExtensionAPI.ts
@@ -1146,9 +1146,17 @@
},
};
+ const protocolGet = Object.getOwnPropertyDescriptor(URL.prototype, 'protocol')?.get;
+ function getProtocol(url: string): string {
+ if (!protocolGet) {
+ throw new Error('URL.protocol is not available');
+ }
+ return protocolGet.call(new URL(url));
+ }
+
function canAccessResource(resource: APIImpl.ResourceData): boolean {
try {
- return extensionInfo.allowFileAccess || (new URL(resource.url)).protocol !== 'file:';
+ return extensionInfo.allowFileAccess || getProtocol(resource.url) !== 'file:';
} catch (e) {
return false;
}
Original Bug Report
Local file access restrictions in chrome.devtools can be bypassed through prototype manipulation.
Steps to reproduce the problem
- Install the attached extension on macOS, and disable “Allow access to file URLs”.
- Open devtools on the new tab opened by the extension.
- Edit the /etc/hosts file highlighted in the sources panel, and save the changes.
- Observe that extension pops up an alert with the new contents of this file.
Problem Description
Various APIs under chrome.devtools use the canAccessResource function (https://chromium.googlesource.com/devtools/devtools-frontend/+/refs/heads/main/front_end/models/extensions/ExtensionAPI.ts#1149) for checking if local resources should be accessible to a given extension. However, the checks in this function can currently be entirely bypassed by overriding URL.prototype’s protocol getter as is done in the attached POC. Since there are no additional checks on the ExtensionServer side when adding event listeners through chrome.devtools.inspectedWindow.onResourceContentCommitted.addListener, an extension can gain access to local resources this way if the user interacts with such resources in the sources panel.
Additional Comments
Previous issues relating to this include:
- https://issues.chromium.org/issues/40060465
- https://issues.chromium.org/issues/40063505 Notably, the latter of those was fixed by https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/4370246, which in turn introduced the possibility to modify the URL prototype to bypass this check.
Summary
Local file access restrictions in chrome.devtools can be bypassed through prototype manipulation.
Additional Data
Category: Security
Chrome Channel: Stable
Regression: N/A