CVE-2026-79137
Overview
Fix not yet public
Original Bug Report
Bypass of 'Allow access to file URLs' via blob workers in chrome.debugger
Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports without the Chrome Security team. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.
Overview: A potential logic error in the chrome.debugger API may allow extensions to bypass the “Allow access to file URLs” permission check. By targeting Web Workers spawned with blob: URLs from a local file:// page, an extension can attach to the worker’s DevTools agent without explicit user consent. This grants the extension arbitrary code execution within the local file context.
Affected files:
chrome/browser/extensions/api/debugger/debugger_api.cccontent/browser/devtools/shared_worker_devtools_agent_host.cccontent/browser/devtools/dedicated_worker_devtools_agent_host.cccontent/browser/devtools/worker_or_worklet_devtools_agent_host.cc
Estimated timestamp from git blame: 2024-08-01
Summary
Extensions using the chrome.debugger API are required to have the “Allow access to file URLs” permission enabled by the user to attach to targets with a file:// origin. A potential logic flaw in the URL validation process allows extensions to bypass this requirement when attaching to Web Workers (SharedWorkers or DedicatedWorkers) that use blob: URLs originating from the file:// scheme (e.g., blob:file:///...).
Root Cause Analysis
The issue is located in ExtensionMayAttachToURL within chrome/browser/extensions/api/debugger/debugger_api.cc.
When verifying if an extension can attach to a target URL, the function correctly accounts for blob: URLs by resolving them to their underlying origin for general restriction checks:
const GURL& url_for_restriction_check =
url.SchemeIsBlob() ? url::Origin::Create(url).GetURL() : url;
if (extension.permissions_data()->IsRestrictedUrl(url_for_restriction_check, error)) {
return false;
}
However, the subsequent check that enforces the user’s explicit file access preference (util::AllowFileAccess) is incorrectly performed against the original URL (url) instead of the resolved origin URL (url_for_restriction_check):
if (url.SchemeIsFile() &&
!util::AllowFileAccess(extension.id(), extension_profile)) {
*error = kRestrictedError;
return false;
}
If the target URL is blob:file:///..., url.SchemeIsFile() evaluates to false because the scheme is blob. Consequently, the permission check is completely skipped.
This bypass specifically affects workers because worker DevTools targets return nullptr for GetWebContents(). During the attachment process, ExtensionMayAttachToAgentHost falls back to calling ExtensionMayAttachToURL using only the worker’s script URL (the blob: URL), avoiding the secondary SiteURL defenses that protect standard tabs and frames.
Potential Exploitation Steps
Note: These are suggested/potential steps, as our tooling agent does not currently have the ability to run code to verify a live proof of concept.
- An attacker publishes an extension requesting the
debuggerandtabspermissions. - A user installs the extension. The “Allow access to file URLs” setting remains disabled (its default state).
- Through social engineering, the attacker tricks the user into downloading and opening a local HTML file (e.g.,
app.html). - Upon opening in Chrome, the
app.htmlfile creates a Web Worker using ablob:URL (which resolves toblob:file:///...). - The extension detects the open tab and identifies the worker DevTools target via
chrome.debugger.getTargets(). - The extension calls
chrome.debugger.attach()on the worker target. Due to the scheme check flaw, the attachment succeeds. - The extension sends a
Runtime.evaluatecommand to the worker, granting the attacker arbitrary code execution within thefile://context, allowing them to read local files or intercept local storage.
Suggested Fix
Update the file access check in ExtensionMayAttachToURL to use the resolved url_for_restriction_check instead of the original url.
if (url_for_restriction_check.SchemeIsFile() &&
!util::AllowFileAccess(extension.id(), extension_profile)) {
*error = kRestrictedError;
return false;
}
Evaluated with Chrome root at commit: 3acbde3302da0cb19488c22c0eb007c791207b4b
Results 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.