CVE-2026-3940
Overview
Files Changed
third_party/blink/renderer/core/inspector/inspector_resource_content_loader.cc
Patch
From a6d7acc60f1c45f3fd24671a5283a1b4cb585948 Mon Sep 17 00:00:00 2001
From: Alex Rudenko <alexrudenko@chromium.org>
Date: Tue, 13 Jan 2026 00:39:51 -0800
Subject: [PATCH] Set resource request mode to kSameOrigin and only use the kOnlyIfCached mode
kOnlyIfCached only works if kSameOrigin is set [1]. The default request
mode is kNoCors[2]. While kNoCors + kOnlyIfCached seems to work for
getting cached resources, this combination does not work when getting
cached requests from the service worker. This CL changes the mode to
kSameOrigin which should allow the request to hit the service worker
cache.
The intention of this part of the resource content loader seems to be to
avoid hitting the network so the combination of kOnlyIfCached +
kSameOrigin would achieve that.
[1]:
[2]:
https: //source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/fetch/request.cc;l=649;drc=f3534bf8a057a7dcb2f239e855fc71b2faf6dddf
https: //source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/fetch/fetch_request_data.h;l=240;drc=4641a043d7914ce31515751c357158d46f4c937a
Fixed: 470574526
Change-Id: Ib92a9df516ee94a8bfbea57f5da17b5e21f9261a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7409996
Commit-Queue: Danil Somsikov <dsv@chromium.org>
Auto-Submit: Alex Rudenko <alexrudenko@chromium.org>
Reviewed-by: Danil Somsikov <dsv@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1568281}
---
diff --git a/third_party/blink/renderer/core/inspector/inspector_resource_content_loader.cc b/third_party/blink/renderer/core/inspector/inspector_resource_content_loader.cc
index 53911c8..7100f9e 100644
--- a/third_party/blink/renderer/core/inspector/inspector_resource_content_loader.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_resource_content_loader.cc
@@ -32,22 +32,6 @@
return !url.IsValid() || url.IsAboutBlankURL() || url.IsAboutSrcdocURL();
}
-bool IsServiceWorkerPresent(Document* document) {
- DocumentLoader* loader = document->Loader();
- if (!loader)
- return false;
-
- if (loader->GetResponse().WasFetchedViaServiceWorker())
- return true;
-
- WebServiceWorkerNetworkProvider* provider =
- loader->GetServiceWorkerNetworkProvider();
- if (!provider)
- return false;
-
- return provider->ControllerServiceWorkerID() >= 0;
-}
-
} // namespace
// NOTE: While this is a RawResourceClient, it loads both raw and css stylesheet
@@ -111,17 +95,11 @@
resource_request = ResourceRequest(document->Url());
resource_request.SetCacheMode(mojom::FetchCacheMode::kOnlyIfCached);
}
+ // kOnlyIfCached requires kSameOrigin mode.
+ resource_request.SetMode(network::mojom::RequestMode::kSameOrigin);
resource_request.SetRequestContext(
mojom::blink::RequestContextType::INTERNAL);
- if (IsServiceWorkerPresent(document)) {
- // If the request is going to be intercepted by a service worker, then
- // don't use only-if-cached. only-if-cached will cause the service worker
- // to throw an exception if it repeats the request, which is a problem:
- // crbug.com/823392 crbug.com/1098389
- resource_request.SetCacheMode(mojom::FetchCacheMode::kDefault);
- }
-
ResourceFetcher* fetcher = document->Fetcher();
const DOMWrapperWorld* world =
Original Bug Report
DevTools Sources panel with Service Worker causes POST to be resent bypassing SameSite=Strict
Steps to reproduce the problem
- Visit https:// jtw.sh/ samesite-post-bypass-ce7139c3/target-sw.php so that cookies are set and a service worker is registered on the target website (
jtw.sh) - Visit the attacker’s site: https:// vps.jorianwoltjer.com/ samesite-post-bypass-ce7139c3/csrf-sw.html
- Right click and choose Inspect to open the DevTools, or press
Ctrl+Shift+IorF12on the keyboard - In the background, a malicious POST request with all cookies has now been sent to the target. See it in the Sources tab viewing the
target-sw.phpfile (see recording samesite-post-bypass-sw.mp4)
Source code for reproducing this locally is also provided in the attached samesite-post-bypass-sw.zip. Run with php -S 0.0.0.0:8000
Problem Description
In DevTools, the Sources panel shows source code of the current page and its associated files. It gets these resources from the cache, or re-fetches them if needed. This new request is initiated from the current site, which is a contradiction if the original navigation came from cross-site. It means that the request for the Sources tab will contain SameSite=Strict cookies even for POST requests.
Weirdly, this re-fetching process seems to only happen if there is a Service Worker registered for the target. Otherwise the error “Content unavailable. Resource was not cached” is shown in place of the content. The service worker doesn’t have to do anything, it just needs to be registered on the target. So any site that uses a service worker and relies on SameSite for Cross-Site Request Forgery (CSRF) protection is vulnerable.
From the attacker a simple top-level form submission is enough. While it shouldn’t work initially, after the DevTools are opened on the resulting page, the request is resent and SameSite=Strict cookies are now sent with the body payload from the attacker.
<form action="..." method="post">
<input type="text" name="name" value="value">
</form>
<script>
document.forms[0].submit();
</script>
This requires some unusual user interaction (F12), but to me still felt unexpected. It should not be possible for an attacker to prepare a request so that it contains their malicious POST body with the user’s SameSite=Strict cookies without it being clearly visible.
The request that the DevTools sources tab sends should inherit the SameSite-ness (initiator?) of the original request so that it is as identical as possible, and doesn’t increase the risk of CSRF.
Summary
DevTools Sources panel with Service Worker causes POST to be resent bypassing SameSite=Strict
Custom Questions
Reporter credit:
Jorian Woltjer, Mian, bug_blitzer
Additional Data
Category: Security
Chrome Channel: Not sure
Regression: No \