High patch-now ~ plausible CVSS 8.8 chrome Type Confusion 🔧 Commit mapped

Overview

High
Severity
8.8
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactType confusion in CacheStorage
DescriptionType confusion in CacheStorage
ComponentCacheStorage
Sub-componentServiceWorker
Bug ClassType Confusion
Action tierpatch-now — corruption primitive, web-reachable in default config (plausible) — upheld by independent review by AI
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Independent review by AIPlausible
Reviewer notes: Commit message only adds a default-off feature flag and never describes a type confusion; the mechanism and corruption primitive rest on the advisory, not the diff. Fix is a feature-disable mitigation, not root-cause validation.
A second, independent AI reviewer (not a human) re-derived this analysis from the fixing commit and the vendor advisory, looking for errors.
Tracker546413288
Fix commitc0b5e8174936 (chromium/src) +103/-1
CWECWE-843 (Type confusion)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CISA KEVNot listed
CreditedSalvatore Gulizia (nickname: Serotav)
Reported2026-08-14 (per vendor advisory)
Fix landed2026-09-10 (public git)
Disclosed2026-09-15
Patch gap5 days — fix public in source before the advisory

Background

Service Worker `respondWith`
a Service Worker can intercept a page’s subresource fetch and satisfy it from arbitrary sources, including fetch() or CacheStorage via cache.match(), returning a body it fully controls for any URL.
V8 code cache (cached metadata)
Blink attaches serialized V8 bytecode (cached_metadata) to a script response so a later load can skip parsing/compilation; the bytecode is only valid when paired with the exact source it was produced from.
`CachedMetadataSender` / `CachedMetadataHandler`
the objects that persist and retrieve a script’s code-cache blob, keyed by URL, deciding whether a response uses the site-isolated code cache or the per-CacheStorage code cache.
`RuntimeEnabledFeatures`
Blink’s compile/runtime feature-gate system; the patch adds ServiceWorkerCodeCache, declared with no status in runtime_enabled_features.json5 and therefore disabled by default.

Root Cause Analysis

Verify before building a PoC

This analysis is consistent with the fixing commit but not fully provable from it: part of the vulnerable path lives in code the fix commit does not touch. Confirm the trigger and the sink against the source before relying on it for exploit development.
What the commit does not establish: Commit message only adds a default-off feature flag and never describes a type confusion; the mechanism and corruption primitive rest on the advisory, not the diff. Fix is a feature-disable mitigation, not root-cause validation.

For subresource responses delivered through a Service Worker, Blink still routed the response through the V8 code-cache machinery: it kept the streamed cached_metadata, built a CachedMetadataHandler, and let ShouldUseIsolatedCodeCache and the sender-creation path treat the response as code-cacheable. Because a Service Worker can return a body for a URL that is decoupled from whatever code-cache blob is stored for that URL (via CacheStorage or a cross-URL respondWith), the bytecode fed to V8 could be mismatched with the actual source text, violating the invariant that cached bytecode is only ever paired with the source that produced it.

The fix adds the default-off ServiceWorkerCodeCache flag and, in every relevant decision point, short-circuits the code-cache path whenever the flag is off and response.WasFetchedViaServiceWorker() is true — resetting cached_metadata, returning early before a handler is created, returning a NullCachedMetadataSender, and forcing ShouldUseIsolatedCodeCache to false. This works because it stops V8 from ever receiving code-cache bytecode for a Service-Worker-mediated response, eliminating the source/bytecode mismatch that produced the type confusion.

Key insight
The core mistake was trusting a Service-Worker-supplied response as a legitimate code-cache participant even though the worker can decouple the served body from the URL-keyed bytecode, letting mismatched bytecode reach V8; the fix removes Service-Worker subresources from the code-cache path entirely (behind a default-off flag), so no mismatched cached metadata can be applied.

Attack Path

  1. Register a controlling Service Worker The attacker’s origin installs a Service Worker that intercepts subresource script fetches with a fetch handler.
  2. Seed a poisoned code-cache entry The worker arranges for a code-cache blob to be stored for a script URL (e.g. via a prior response or a CacheStorage entry) that corresponds to source text different from what will later be served.
  3. Serve a mismatched body On a later load the worker responds with content for that URL whose actual source no longer matches the stored bytecode, using respondWith(cache.match(...)) or a cross-URL fetch response so the code-cache lookup still hits. Pre-patch, ShouldUseIsolatedCodeCache/CreateCachedMetadataSender accepted this and the stale cached_metadata was retained.
  4. V8 consumes mismatched bytecode V8 deserializes the URL-keyed code cache and pairs it with the wrong source, producing a type confusion in the renderer where object layouts assumed by the bytecode do not match the real objects. (inferred — the diff only removes the code-cache path; it does not itself show the confusion sink.)
  5. Memory corruption / control The type confusion is leveraged into a read/write primitive and potentially renderer code execution. (inferred — not demonstrated by the patch.)

Impact Assessment

An attacker who can register a Service Worker on a page (in-scope web content) gains a type confusion in the renderer process by causing V8 to apply code-cache bytecode that was not produced from the source actually served. Preconditions are a controllable Service Worker and the ability to influence the URL-keyed code-cache contents; exploitation to a memory-corruption primitive or code execution is (inferred) and not established by the diff. The vendor advisory rates this high severity and does not report in-the-wild exploitation; NVD scores it CVSS 8.8. A formal severity are not stated in the provided materials; the advisory classifies it as a type confusion in CacheStorage.

Changed Functions

FunctionChangeNotes
if
third_party/blink/renderer/bindings/core/v8/script_streamer.cc
modified
ServiceWorkerV8CodeCacheForCacheStorageTest
content/browser/service_worker/service_worker_browsertest.cc
modified
ServiceWorkerV8CodeCacheForCacheStorageTest
content/browser/service_worker/service_worker_browsertest.cc
modified
TEST
third_party/blink/renderer/core/loader/resource/script_resource_test.cc
modified

Files Changed

  • third_party/blink/renderer/platform/runtime_enabled_features.json5
  • third_party/blink/renderer/platform/loader/fetch/url_loader/cached_metadata_handler_test.cc
  • third_party/blink/renderer/bindings/core/v8/script_streamer.cc
  • third_party/blink/renderer/core/loader/resource/script_resource.cc
  • content/browser/service_worker/service_worker_browsertest.cc
  • third_party/blink/renderer/platform/loader/fetch/url_loader/cached_metadata_handler.cc
  • third_party/blink/renderer/core/loader/resource/script_resource_test.cc

Audit Directions

  • Source/bytecode pairing across indirection
    Audit every path where V8 code cache (or any serialized metadata) is keyed by URL but the body can be supplied by an intermediary (Service Workers, CacheStorage, prefetch, back/forward cache), ensuring the cached blob cannot be applied to a different source.
  • `WasFetchedViaServiceWorker` decision points
    Grep for uses of WasFetchedViaServiceWorker() and was_fetched_via_service_worker in loader/caching code and verify each treats Service-Worker responses as untrusted for caching, not as ordinary same-origin responses.
  • Feature-gate completeness
    When a mitigation is a distributed flag check, confirm every branch that reaches the sensitive sink is gated; a single missed decision point (streamer, resource, sender, or ShouldUseIsolatedCodeCache) would reopen the mismatch.
From c0b5e81749361a9c8a79990f2c721a16d141882c Mon Sep 17 00:00:00 2001
From: Takashi Nakayama <[email protected]>
Date: Thu, 10 Sep 2026 00:32:02 -0700
Subject: [PATCH] ServiceWorker: Add feature flag to disable Code Cache

This CL adds a new runtime enabled feature, `ServiceWorkerCodeCache` to
disable Code Caching for subresource requests through Service Workers.
The new feature is disabled by default.

Bug: 558367547, 546413288, 547815507, 558342353
Change-Id: I2a3b7fbf8c489eec00bce668abb3a7cf438d9f44
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8377021
Reviewed-by: Yoshisato Yanagisawa <[email protected]>
Reviewed-by: Shunya Shishido <[email protected]>
Commit-Queue: Takashi Nakayama <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1695233}
---
diff --git a/third_party/blink/renderer/bindings/core/v8/script_streamer.cc b/third_party/blink/renderer/bindings/core/v8/script_streamer.cc
index aabdaa9e..615c445 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_streamer.cc
+++ b/third_party/blink/renderer/bindings/core/v8/script_streamer.cc
@@ -58,6 +58,7 @@
 #include "third_party/blink/renderer/platform/loader/fetch/response_body_loader.h"
 #include "third_party/blink/renderer/platform/loader/fetch/script_cached_metadata_handler.h"
 #include "third_party/blink/renderer/platform/network/mime/mime_type_registry.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
 #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
 #include "third_party/blink/renderer/platform/scheduler/public/worker_pool.h"
@@ -1874,6 +1875,11 @@
     return false;
   }
 
+  if (!RuntimeEnabledFeatures::ServiceWorkerCodeCacheEnabled() &&
+      head->was_fetched_via_service_worker) {
+    cached_metadata.reset();
+  }
+
   if (is_valid_wasm_mime_type) {
     // TODO(https://crbug.com/42204365): Add support for code caching.
     // For now, we clear cached_metadata to avoid unintended side-effects.
diff --git a/third_party/blink/renderer/core/loader/resource/script_resource.cc b/third_party/blink/renderer/core/loader/resource/script_resource.cc
index 39a58fe..8b9f1616 100644
--- a/third_party/blink/renderer/core/loader/resource/script_resource.cc
+++ b/third_party/blink/renderer/core/loader/resource/script_resource.cc
@@ -59,6 +59,7 @@
 #include "third_party/blink/renderer/platform/loader/fetch/webui_bundled_cached_metadata_handler.h"
 #include "third_party/blink/renderer/platform/loader/subresource_integrity.h"
 #include "third_party/blink/renderer/platform/network/mime/mime_type_registry.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
@@ -411,6 +412,10 @@
   }
 
   cached_metadata_handler_ = nullptr;
+  if (response.WasFetchedViaServiceWorker() &&
+      !RuntimeEnabledFeatures::ServiceWorkerCodeCacheEnabled()) {
+    return;
+  }
   // Currently we support the metadata caching only for HTTP family and any
   // schemes defined by SchemeRegistry as requiring a hash check.
   bool http_family = GetResourceRequest().Url().ProtocolIsInHttpFamily() &&
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/cached_metadata_handler.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/cached_metadata_handler.cc
index 3707f3fc..5ef2f37d 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/cached_metadata_handler.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/cached_metadata_handler.cc
@@ -12,6 +12,7 @@
 #include "third_party/blink/public/platform/web_url.h"
 #include "third_party/blink/renderer/platform/loader/fetch/code_cache_host.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
 namespace blink {
 
@@ -131,6 +132,11 @@
     const ResourceResponse& response,
     mojom::blink::CodeCacheType code_cache_type,
     scoped_refptr<const SecurityOrigin> requestor_origin) {
+  if (!RuntimeEnabledFeatures::ServiceWorkerCodeCacheEnabled() &&
+      response.WasFetchedViaServiceWorker()) {
+    return std::make_unique<NullCachedMetadataSender>();
+  }
+
   // Non-ServiceWorker scripts and passthrough SW responses use the site
   // isolated code cache.
   if (!response.WasFetchedViaServiceWorker() ||
@@ -171,6 +177,11 @@
 bool ShouldUseIsolatedCodeCache(
     mojom::blink::RequestContextType request_context,
     const ResourceResponse& response) {
+  if (!RuntimeEnabledFeatures::ServiceWorkerCodeCacheEnabled() &&
+      response.WasFetchedViaServiceWorker()) {
+    return false;
+  }
+
   // Service worker script has its own code cache.
   if (request_context == mojom::blink::RequestContextType::SERVICE_WORKER)
     return false;
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 626e074..85ea1fb 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -5711,6 +5711,10 @@
       status: "experimental",
     },
     {
+      // V8 Code Cache for resource requests passing through Service Worker.
+      name: "ServiceWorkerCodeCache",
+    },
+    {
       // Support for Service Worker APIs in Dedicated Workers.
       // See https://chromestatus.com/feature/6497653025931264
       // See https://issues.chromium.org/issues/40364838
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index 42aaa111..01c4800 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -3399,7 +3399,10 @@
 class ServiceWorkerV8CodeCacheForCacheStorageTest
     : public ServiceWorkerBrowserTest {
  public:
-  ServiceWorkerV8CodeCacheForCacheStorageTest() = default;
+  ServiceWorkerV8CodeCacheForCacheStorageTest() {
+    feature_list_.InitAndEnableFeature(
+        blink::features::kServiceWorkerCodeCache);
+  }
 
   ServiceWorkerV8CodeCacheForCacheStorageTest(
       const ServiceWorkerV8CodeCacheForCacheStorageTest&) = delete;
@@ -3474,6 +3477,8 @@
         partition->GetCacheStorageControl(), embedded_test_server()->base_url(),
         std::string("cache_name"), embedded_test_server()->GetURL(kScriptUrl));
   }
+
+  base::test::ScopedFeatureList feature_list_;
 };
 
 const char ServiceWorkerV8CodeCacheForCacheStorageTest::kPageUrl[] =
diff --git a/third_party/blink/renderer/core/loader/resource/script_resource_test.cc b/third_party/blink/renderer/core/loader/resource/script_resource_test.cc
index df582f1..4a1d54b 100644
--- a/third_party/blink/renderer/core/loader/resource/script_resource_test.cc
+++ b/third_party/blink/renderer/core/loader/resource/script_resource_test.cc
@@ -9,6 +9,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
 #include "third_party/blink/renderer/platform/loader/fetch/url_loader/cached_metadata_handler.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
 #include "third_party/blink/renderer/platform/testing/task_environment.h"
 #include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
@@ -323,5 +324,35 @@
   enable_webui_bundled_code_caching(false);
 }
 
+TEST(ScriptResourceTest, ServiceWorkerCodeCacheFlag) {
+  test::TaskEnvironment task_environment;
+  V8TestingScope scope;
+  const KURL url("https://www.example.com/sw-script.js");
+
+  {
+    ScopedServiceWorkerCodeCacheForTest scoped_feature(false);
+    ScriptResource* resource =
+        ScriptResource::CreateForTest(scope.GetIsolate(), url, Utf8Encoding());
+    ResourceResponse response(url);
+    response.SetHttpStatusCode(200);
+    response.SetWasFetchedViaServiceWorker(true);
+
+    resource->ResponseReceived(response);
+    EXPECT_FALSE(resource->CacheHandler());
+  }
+
+  {
+    ScopedServiceWorkerCodeCacheForTest scoped_feature(true);
+    ScriptResource* resource =
+        ScriptResource::CreateForTest(scope.GetIsolate(), url, Utf8Encoding());
+    ResourceResponse response(url);
+    response.SetHttpStatusCode(200);
+    response.SetWasFetchedViaServiceWorker(true);
+
+    resource->ResponseReceived(response);
+    EXPECT_TRUE(resource->CacheHandler());
+  }
+}
+
 }  // namespace
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/cached_metadata_handler_test.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/cached_metadata_handler_test.cc
index ba13a0e..a4320bb 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/cached_metadata_handler_test.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/cached_metadata_handler_test.cc
@@ -9,12 +9,14 @@
 #include "components/persistent_cache/pending_backend.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
 #include "third_party/blink/public/mojom/loader/code_cache.mojom-blink.h"
 #include "third_party/blink/public/platform/url_conversion.h"
 #include "third_party/blink/public/platform/web_url.h"
 #include "third_party/blink/renderer/platform/loader/fetch/code_cache_host.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
 #include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -136,6 +138,7 @@
 TEST(
     CachedMetadataHandlerTest,
     SendsMetadataToPlatformWhenFetchedViaServiceWorkerWithPassThroughResponse) {
+  ScopedServiceWorkerCodeCacheForTest scoped_feature(true);
   MockGeneratedCodeCache mock_disk_cache;
 
   // Equivalent to service worker calling respondWith(fetch(evt.request.url));
@@ -151,6 +154,7 @@
 TEST(
     CachedMetadataHandlerTest,
     DoesNotSendMetadataToPlatformWhenFetchedViaServiceWorkerWithDifferentURLResponse) {
+  ScopedServiceWorkerCodeCacheForTest scoped_feature(true);
   MockGeneratedCodeCache mock_disk_cache;
 
   // Equivalent to service worker calling respondWith(fetch(some_different_url))
@@ -166,6 +170,7 @@
 
 TEST(CachedMetadataHandlerTest,
      SendsMetadataToPlatformWhenFetchedViaServiceWorkerWithCacheResponse) {
+  ScopedServiceWorkerCodeCacheForTest scoped_feature(true);
   MockGeneratedCodeCache mock_disk_cache;
 
   // Equivalent to service worker calling respondWith(cache.match(some_url));
@@ -179,9 +184,25 @@
   EXPECT_EQ(1u, mock_disk_cache.CacheStorageCachedURLs().size());
 }
 
+TEST(CachedMetadataHandlerTest,
+     DoesNotSendMetadataToPlatformWhenServiceWorkerCodeCacheDisabled) {
+  ScopedServiceWorkerCodeCacheForTest scoped_feature(false);
+  MockGeneratedCodeCache mock_disk_cache;
+
+  ResourceResponse response(CreateTestResourceResponse());
+  response.SetWasFetchedViaServiceWorker(true);
+  response.SetUrlListViaServiceWorker({response.CurrentRequestUrl()});
+  response.SetCacheStorageCacheName("dummy");
+
+  SendDataFor(response, &mock_disk_cache);
+  EXPECT_EQ(0u, mock_disk_cache.CachedURLs().size());
+  EXPECT_EQ(0u, mock_disk_cache.CacheStorageCachedURLs().size());
+}
+
 TEST(
     CachedMetadataHandlerTest,
     DoesNotSendMetadataToPlatformWhenFetchedViaServiceWorkerWithSyntheticCacheResponse) {
+  ScopedServiceWorkerCodeCacheForTest scoped_feature(true);
   MockGeneratedCodeCache mock_disk_cache;
 
   // Equivalent to service worker calling
@@ -198,6 +219,7 @@
 TEST(
     CachedMetadataHandlerTest,
     DoesNotSendMetadataToPlatformWhenFetchedViaServiceWorkerWithDifferentURLCacheResponse) {
+  ScopedServiceWorkerCodeCacheForTest scoped_feature(true);
   MockGeneratedCodeCache mock_disk_cache;
 
   // Equivalent to service worker calling
@@ -213,5 +235,23 @@
   EXPECT_EQ(0u, mock_disk_cache.CacheStorageCachedURLs().size());
 }
 
+TEST(CachedMetadataHandlerTest,
+     ShouldUseIsolatedCodeCacheRespectsServiceWorkerCodeCacheFlag) {
+  ResourceResponse response(CreateTestResourceResponse());
+  response.SetWasFetchedViaServiceWorker(true);
+  response.SetUrlListViaServiceWorker({response.CurrentRequestUrl()});
+
+  {
+    ScopedServiceWorkerCodeCacheForTest scoped_feature(false);
+    EXPECT_FALSE(ShouldUseIsolatedCodeCache(
+        mojom::blink::RequestContextType::SCRIPT, response));
+  }
+  {
+    ScopedServiceWorkerCodeCacheForTest scoped_feature(true);
+    EXPECT_TRUE(ShouldUseIsolatedCodeCache(
+        mojom::blink::RequestContextType::SCRIPT, response));
+  }
+}
+
 }  // namespace
 }  // namespace blink
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index 42aaa111..01c4800 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -3399,7 +3399,10 @@
 class ServiceWorkerV8CodeCacheForCacheStorageTest
     : public ServiceWorkerBrowserTest {
  public:
-  ServiceWorkerV8CodeCacheForCacheStorageTest() = default;
+  ServiceWorkerV8CodeCacheForCacheStorageTest() {
+    feature_list_.InitAndEnableFeature(
+        blink::features::kServiceWorkerCodeCache);
+  }
 
   ServiceWorkerV8CodeCacheForCacheStorageTest(
       const ServiceWorkerV8CodeCacheForCacheStorageTest&) = delete;
@@ -3474,6 +3477,8 @@
         partition->GetCacheStorageControl(), embedded_test_server()->base_url(),
         std::string("cache_name"), embedded_test_server()->GetURL(kScriptUrl));
   }
+
+  base::test::ScopedFeatureList feature_list_;
 };
 
 const char ServiceWorkerV8CodeCacheForCacheStorageTest::kPageUrl[] =
diff --git a/third_party/blink/renderer/core/loader/resource/script_resource_test.cc b/third_party/blink/renderer/core/loader/resource/script_resource_test.cc
index df582f1..4a1d54b 100644
--- a/third_party/blink/renderer/core/loader/resource/script_resource_test.cc
+++ b/third_party/blink/renderer/core/loader/resource/script_resource_test.cc
@@ -9,6 +9,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
 #include "third_party/blink/renderer/platform/loader/fetch/url_loader/cached_metadata_handler.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
 #include "third_party/blink/renderer/platform/testing/task_environment.h"
 #include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
@@ -323,5 +324,35 @@
   enable_webui_bundled_code_caching(false);
 }
 
+TEST(ScriptResourceTest, ServiceWorkerCodeCacheFlag) {
+  test::TaskEnvironment task_environment;
+  V8TestingScope scope;
+  const KURL url("https://www.example.com/sw-script.js");
+
+  {
+    ScopedServiceWorkerCodeCacheForTest scoped_feature(false);
+    ScriptResource* resource =
+        ScriptResource::CreateForTest(scope.GetIsolate(), url, Utf8Encoding());
+    ResourceResponse response(url);
+    response.SetHttpStatusCode(200);
+    response.SetWasFetchedViaServiceWorker(true);
+
+    resource->ResponseReceived(response);
+    EXPECT_FALSE(resource->CacheHandler());
+  }
+
+  {
+    ScopedServiceWorkerCodeCacheForTest scoped_feature(true);
+    ScriptResource* resource =
+        ScriptResource::CreateForTest(scope.GetIsolate(), url, Utf8Encoding());
+    ResourceResponse response(url);
+    response.SetHttpStatusCode(200);
+    response.SetWasFetchedViaServiceWorker(true);
+
+    resource->ResponseReceived(response);
+    EXPECT_TRUE(resource->CacheHandler());
+  }
+}
+
 }  // namespace
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/cached_metadata_handler_test.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/cached_metadata_handler_test.cc
index ba13a0e..a4320bb 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/cached_metadata_handler_test.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/cached_metadata_handler_test.cc
@@ -9,12 +9,14 @@
 #include "components/persistent_cache/pending_backend.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
 #include "third_party/blink/public/mojom/loader/code_cache.mojom-blink.h"
 #include "third_party/blink/public/platform/url_conversion.h"
 #include "third_party/blink/public/platform/web_url.h"
 #include "third_party/blink/renderer/platform/loader/fetch/code_cache_host.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
 #include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -136,6 +138,7 @@
 TEST(
     CachedMetadataHandlerTest,
     SendsMetadataToPlatformWhenFetchedViaServiceWorkerWithPassThroughResponse) {
+  ScopedServiceWorkerCodeCacheForTest scoped_feature(true);
   MockGeneratedCodeCache mock_disk_cache;
 
   // Equivalent to service worker calling respondWith(fetch(evt.request.url));
@@ -151,6 +154,7 @@
 TEST(
     CachedMetadataHandlerTest,
     DoesNotSendMetadataToPlatformWhenFetchedViaServiceWorkerWithDifferentURLResponse) {
+  ScopedServiceWorkerCodeCacheForTest scoped_feature(true);
   MockGeneratedCodeCache mock_disk_cache;
 
   // Equivalent to service worker calling respondWith(fetch(some_different_url))
@@ -166,6 +170,7 @@
 
 TEST(CachedMetadataHandlerTest,
      SendsMetadataToPlatformWhenFetchedViaServiceWorkerWithCacheResponse) {
+  ScopedServiceWorkerCodeCacheForTest scoped_feature(true);
   MockGeneratedCodeCache mock_disk_cache;
 
   // Equivalent to service worker calling respondWith(cache.match(some_url));
@@ -179,9 +184,25 @@
   EXPECT_EQ(1u, mock_disk_cache.CacheStorageCachedURLs().size());
 }
 
+TEST(CachedMetadataHandlerTest,
+     DoesNotSendMetadataToPlatformWhenServiceWorkerCodeCacheDisabled) {
+  ScopedServiceWorkerCodeCacheForTest scoped_feature(false);
+  MockGeneratedCodeCache mock_disk_cache;
+
+  ResourceResponse response(CreateTestResourceResponse());
+  response.SetWasFetchedViaServiceWorker(true);
+  response.SetUrlListViaServiceWorker({response.CurrentRequestUrl()});
+  response.SetCacheStorageCacheName("dummy");
+
+  SendDataFor(response, &mock_disk_cache);
+  EXPECT_EQ(0u, mock_disk_cache.CachedURLs().size());
+  EXPECT_EQ(0u, mock_disk_cache.CacheStorageCachedURLs().size());
+}
+
 TEST(
     CachedMetadataHandlerTest,
     DoesNotSendMetadataToPlatformWhenFetchedViaServiceWorkerWithSyntheticCacheResponse) {
+  ScopedServiceWorkerCodeCacheForTest scoped_feature(true);
   MockGeneratedCodeCache mock_disk_cache;
 
   // Equivalent to service worker calling
@@ -198,6 +219,7 @@
 TEST(
     CachedMetadataHandlerTest,
     DoesNotSendMetadataToPlatformWhenFetchedViaServiceWorkerWithDifferentURLCacheResponse) {
+  ScopedServiceWorkerCodeCacheForTest scoped_feature(true);
   MockGeneratedCodeCache mock_disk_cache;
 
   // Equivalent to service worker calling
@@ -213,5 +235,23 @@
   EXPECT_EQ(0u, mock_disk_cache.CacheStorageCachedURLs().size());
 }
 
+TEST(CachedMetadataHandlerTest,
+     ShouldUseIsolatedCodeCacheRespectsServiceWorkerCodeCacheFlag) {
+  ResourceResponse response(CreateTestResourceResponse());
+  response.SetWasFetchedViaServiceWorker(true);
+  response.SetUrlListViaServiceWorker({response.CurrentRequestUrl()});
+
+  {
+    ScopedServiceWorkerCodeCacheForTest scoped_feature(false);
+    EXPECT_FALSE(ShouldUseIsolatedCodeCache(
+        mojom::blink::RequestContextType::SCRIPT, response));
+  }
+  {
+    ScopedServiceWorkerCodeCacheForTest scoped_feature(true);
+    EXPECT_TRUE(ShouldUseIsolatedCodeCache(
+        mojom::blink::RequestContextType::SCRIPT, response));
+  }
+}
+
 }  // namespace
 }  // namespace blink
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.