Overview

Medium
Severity
9.6
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in ServiceWorker
DescriptionUse after free in ServiceWorker
ComponentServiceWorker
Sub-componentServiceWorker
Bug ClassUAF
Action tierpatch-now — corruption primitive, web-reachable in default config (confirmed) — 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 AIConfirmed
A second, independent AI reviewer (not a human) re-derived this analysis from the fixing commit and the vendor advisory, looking for errors.
Tracker522957054
Fix commit45038ff19def (chromium/src) +106/-0
CWECWE-416 (Use-after-free)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H
CISA KEVNot listed
CreditedGoogle
Reported2026-06-11 (per vendor advisory)
Fix landed2026-07-07 (public git)
Disclosed2026-08-25
Patch gap49 days — fix public in source before the advisory

Background

`ServiceWorkerSingleScriptUpdateChecker`
a browser-process object that fetches one service-worker script during an update check and compares it byte-for-byte against the stored copy, reporting the outcome through a ResultCallback.
`ServiceWorkerCacheWriter::MaybeWriteHeaders`
the routine that writes the fetched response headers to storage; it can complete synchronously and invoke its completion callback inline when the storage writer mojo remote is already disconnected.
`ResultCallback`
the caller-supplied callback the checker runs to report a Result; the owner is explicitly permitted to destroy the checker from inside this callback.
`base::WeakPtr`
a smart pointer that becomes null once the pointed-to object is destroyed, letting code detect re-entrant destruction of this.

Root Cause Analysis

In OnReceiveResponse(), the checker stored network_accessed_ and then called WriteHeaders(std::move(response_head)), expecting the write to complete asynchronously. However, when the storage ServiceWorkerResourceWriter remote is disconnected, the underlying ServiceWorkerCacheWriter::MaybeWriteHeaders completes synchronously and runs the completion chain, which ends up invoking the checker’s ResultCallback inline. The owner is allowed to (and does) delete the checker from within that callback, so control returns into OnReceiveResponse() with this already freed, and the subsequent statements (e.g. if (!consumer) return; and further member accesses) touch freed memory — a use-after-free.

The fix takes a base::WeakPtr before WriteHeaders() and returns immediately afterward if !weak_this, so no members are touched once this may have been destroyed.

Key insight
The core mistake was treating a header write as always-asynchronous and continuing to use this after it returned, when a disconnected storage remote makes the write complete synchronously and re-entrantly destroy the checker; a WeakPtr guard after WriteHeaders() detects that destruction and bails out.

Attack Path

  1. Trigger a service-worker update check Attacker-controlled site conditions cause the browser to fetch a service-worker script through ServiceWorkerSingleScriptUpdateChecker, reaching OnReceiveResponse() when the network response arrives.
  2. Force synchronous header-write failure The storage writer remote is disconnected before the response is processed (the regression test models this via writer_receiver.reset()), so MaybeWriteHeaders completes synchronously with failure instead of posting a task.
  3. Re-entrant destruction in the callback The synchronous completion runs the ResultCallback with Result::kFailed, and the owner destroys the checker from inside that callback (the test does checker.reset()).
  4. Use-after-free on return Execution unwinds back into OnReceiveResponse() after WriteHeaders(), where the now-freed this is dereferenced by the following statements (write primitive / further exploitation is (inferred), not shown by the patch).

Impact Assessment

An attacker who can steer a service-worker update to fail its header write synchronously can cause a use-after-free of the ServiceWorkerSingleScriptUpdateChecker in the privileged browser process. The advisory classifies this as a use-after-free in ServiceWorker; exploited-in-the-wild status is not stated, and any escalation to controlled read/write or code execution is (inferred) beyond what the diff demonstrates. Preconditions are an update check in progress and a disconnected storage writer remote that forces the synchronous-completion path.

Changed Functions

FunctionChangeNotes
if
content/browser/service_worker/service_worker_single_script_update_checker.cc
modified
ASSERT_TRUE
content/browser/service_worker/service_worker_single_script_update_checker_unittest.cc
modified
ServiceWorkerSingleScriptUpdateCheckerSha256ChecksumTest
content/browser/service_worker/service_worker_single_script_update_checker_unittest.cc
modified

Files Changed

  • content/browser/service_worker/service_worker_single_script_update_checker.cc
  • content/browser/service_worker/service_worker_single_script_update_checker_unittest.cc
  • content/browser/service_worker/service_worker_single_script_update_checker.h

Audit Directions

  • Assumed-async completions
    Flag any callback-driven routine (mojo writes, cache/storage operations) that continues to touch this after the call returns, since a disconnected/empty remote can make it complete synchronously and re-enter.
  • Owner-destroys-in-callback contracts
    For every ResultCallback/completion callback whose contract permits the owner to destroy the object, verify each caller guards subsequent member access with a WeakPtr or an early return.
  • Service-worker update/compare paths
    Audit sibling methods in ServiceWorkerSingleScriptUpdateChecker and ServiceWorkerCacheWriter that chain into the result callback for the same synchronous-reentrancy pattern after remote disconnection.
From 45038ff19def4d325e7ec9a7fe3307e0dc74efd7 Mon Sep 17 00:00:00 2001
From: Yoshisto Yanagisawa <[email protected]>
Date: Mon, 06 Jul 2026 23:42:57 -0700
Subject: [PATCH] ServiceWorker: Handle re-entrant destruction in update checker

ServiceWorkerCacheWriter::MaybeWriteHeaders() can run its completion callback synchronously when the storage writer remote is disconnected. The callback chain ends up running the checker's ResultCallback, and the owner is allowed to destroy the checker from within that callback. Stop touching members in OnReceiveResponse() after WriteHeaders() returns if |this| has been destroyed.

Bug: 522957054

TAG=agy

CONV=f42520bd-6803-438a-a9c7-e7e32fcbc7e1

Change-Id: I5a9bb646212e87c5a800c5d4ad5099a66953f434
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8020222
Reviewed-by: Shunya Shishido <[email protected]>
Commit-Queue: Yoshisato Yanagisawa <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1657711}
---
diff --git a/content/browser/service_worker/service_worker_single_script_update_checker.cc b/content/browser/service_worker/service_worker_single_script_update_checker.cc
index afe55f7..7863c4e 100644
--- a/content/browser/service_worker/service_worker_single_script_update_checker.cc
+++ b/content/browser/service_worker/service_worker_single_script_update_checker.cc
@@ -295,7 +295,14 @@
 
   network_accessed_ = response_head->network_accessed;
 
+  // WriteHeaders() may complete synchronously and run the result callback,
+  // which is allowed to destroy |this|.
+  base::WeakPtr<ServiceWorkerSingleScriptUpdateChecker> weak_this =
+      weak_factory_.GetWeakPtr();
   WriteHeaders(std::move(response_head));
+  if (!weak_this) {
+    return;
+  }
 
   if (!consumer)
     return;
@@ -427,6 +434,12 @@
   }
 }
 
+void ServiceWorkerSingleScriptUpdateChecker::FlushRemotesForTesting() {
+  if (cache_writer_) {
+    cache_writer_->FlushRemotesForTesting();  // IN-TEST
+  }
+}
+
 //------------------------------------------------------------------------------
 
 void ServiceWorkerSingleScriptUpdateChecker::WriteHeaders(
diff --git a/content/browser/service_worker/service_worker_single_script_update_checker.h b/content/browser/service_worker/service_worker_single_script_update_checker.h
index 077ba46..a0c9374 100644
--- a/content/browser/service_worker/service_worker_single_script_update_checker.h
+++ b/content/browser/service_worker/service_worker_single_script_update_checker.h
@@ -191,6 +191,7 @@
   const scoped_refptr<PolicyContainerHost> policy_container_host() const {
     return policy_container_host_;
   }
+  void FlushRemotesForTesting();
 
   static const char* ResultToString(Result result);
 
diff --git a/content/browser/service_worker/service_worker_single_script_update_checker_unittest.cc b/content/browser/service_worker/service_worker_single_script_update_checker_unittest.cc
index 858a3bb..2771271 100644
--- a/content/browser/service_worker/service_worker_single_script_update_checker_unittest.cc
+++ b/content/browser/service_worker/service_worker_single_script_update_checker_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/functional/bind.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
+#include "base/test/run_until.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/browser/service_worker/service_worker_test_utils.h"
 #include "content/public/test/browser_task_environment.h"
@@ -124,6 +125,45 @@
     return remote;
   }
 
+  std::unique_ptr<ServiceWorkerSingleScriptUpdateChecker>
+  CreateSingleScriptUpdateCheckerWithCallback(
+      const char* url,
+      const GURL& scope,
+      std::unique_ptr<MockServiceWorkerResourceReader> compare_reader,
+      std::unique_ptr<MockServiceWorkerResourceReader> copy_reader,
+      mojo::Remote<storage::mojom::ServiceWorkerResourceWriter> writer,
+      network::TestURLLoaderFactory* loader_factory,
+      ServiceWorkerSingleScriptUpdateChecker::ResultCallback callback) {
+    auto fetch_client_settings_object =
+        blink::mojom::FetchClientSettingsObject::New(
+            []() {
+              auto policies = blink::mojom::PolicyContainerPolicies::New();
+              policies->referrer_policy =
+                  network::mojom::ReferrerPolicy::kDefault;
+              return policies;
+            }(),
+            GURL(url), blink::mojom::InsecureRequestsPolicy::kDoNotUpgrade);
+    return std::make_unique<ServiceWorkerSingleScriptUpdateChecker>(
+        GURL(url), /*is_main_script=*/true, GURL(url), scope,
+        /*force_bypass_cache=*/false, blink::mojom::ScriptType::kClassic,
+        blink::mojom::ServiceWorkerUpdateViaCache::kNone,
+        std::move(fetch_client_settings_object),
+        /*time_since_last_check=*/base::TimeDelta(), browser_context_.get(),
+        base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+            loader_factory),
+        WrapReader(std::move(compare_reader)),
+        WrapReader(std::move(copy_reader)), std::move(writer),
+        /*writer_resource_id=*/0,
+        ServiceWorkerSingleScriptUpdateChecker::ScriptChecksumUpdateOption::
+            kDefault,
+        blink::StorageKey::Create(url::Origin::Create(scope),
+                                  net::SchemefulSite(scope),
+                                  blink::mojom::AncestorChainBit::kSameSite,
+                                  /*third_party_partitioning_allowed=*/true),
+        /*network_restrictions_id=*/std::nullopt, PolicyContainerPolicies(),
+        std::move(callback));
+  }
+
   mojo::Remote<storage::mojom::ServiceWorkerResourceWriter> WrapWriter(
       std::unique_ptr<MockServiceWorkerResourceWriter> writer) {
     mojo::Remote<storage::mojom::ServiceWorkerResourceWriter> remote;
@@ -1450,6 +1490,58 @@
   }
 }
 
+// Tests that the checker can be safely destroyed from inside its result
+// callback when writing the response headers to storage fails synchronously
+// (e.g., the storage writer connection has gone away).
+TEST_F(ServiceWorkerSingleScriptUpdateCheckerTest,
+       DestroyedInCallbackOnSynchronousHeaderWriteFailure) {
+  auto loader_factory = std::make_unique<network::TestURLLoaderFactory>();
+  auto compare_reader = std::make_unique<MockServiceWorkerResourceReader>();
+  auto copy_reader = std::make_unique<MockServiceWorkerResourceReader>();
+
+  mojo::Remote<storage::mojom::ServiceWorkerResourceWriter> writer_remote;
+  auto writer_receiver = writer_remote.BindNewPipeAndPassReceiver();
+
+  std::unique_ptr<ServiceWorkerSingleScriptUpdateChecker> checker;
+  std::optional<ServiceWorkerSingleScriptUpdateChecker::Result> result;
+  checker = CreateSingleScriptUpdateCheckerWithCallback(
+      kScriptURL, GURL(kScope), std::move(compare_reader),
+      std::move(copy_reader), std::move(writer_remote), loader_factory.get(),
+      base::BindLambdaForTesting(
+          [&](const GURL&,
+              ServiceWorkerSingleScriptUpdateChecker::Result compare_result,
+              std::unique_ptr<
+                  ServiceWorkerSingleScriptUpdateChecker::FailureInfo>,
+              std::unique_ptr<
+                  ServiceWorkerSingleScriptUpdateChecker::PausedState>,
+              const std::optional<std::string>&) {
+            result = compare_result;
+            // The owner may destroy the checker synchronously in response to
+            // the result.
+            checker.reset();
+          }));
+
+  // Disconnect the storage writer before the network response arrives so that
+  // writing headers fails synchronously.
+  writer_receiver.reset();
+  checker->FlushRemotesForTesting();
+  ASSERT_FALSE(result.has_value());
+
+  auto head = network::mojom::URLResponseHead::New();
+  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+      net::HttpUtil::AssembleRawHeaders(kSuccessHeader));
+  head->headers->GetMimeType(&head->mime_type);
+  head->parsed_headers = network::mojom::ParsedHeaders::New();
+  loader_factory->SimulateResponseForPendingRequest(
+      GURL(kScriptURL), network::URLLoaderCompletionStatus(net::OK),
+      std::move(head), "abcdef");
+  ASSERT_TRUE(base::test::RunUntil([&]() { return result.has_value(); }));
+
+  EXPECT_EQ(result.value(),
+            ServiceWorkerSingleScriptUpdateChecker::Result::kFailed);
+  EXPECT_FALSE(checker);
+}
+
 class ServiceWorkerSingleScriptUpdateCheckerSha256ChecksumTest
     : public ServiceWorkerSingleScriptUpdateCheckerTest,
       public testing::WithParamInterface<
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/content/browser/service_worker/service_worker_single_script_update_checker_unittest.cc b/content/browser/service_worker/service_worker_single_script_update_checker_unittest.cc
index 858a3bb..2771271 100644
--- a/content/browser/service_worker/service_worker_single_script_update_checker_unittest.cc
+++ b/content/browser/service_worker/service_worker_single_script_update_checker_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/functional/bind.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
+#include "base/test/run_until.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/browser/service_worker/service_worker_test_utils.h"
 #include "content/public/test/browser_task_environment.h"
@@ -124,6 +125,45 @@
     return remote;
   }
 
+  std::unique_ptr<ServiceWorkerSingleScriptUpdateChecker>
+  CreateSingleScriptUpdateCheckerWithCallback(
+      const char* url,
+      const GURL& scope,
+      std::unique_ptr<MockServiceWorkerResourceReader> compare_reader,
+      std::unique_ptr<MockServiceWorkerResourceReader> copy_reader,
+      mojo::Remote<storage::mojom::ServiceWorkerResourceWriter> writer,
+      network::TestURLLoaderFactory* loader_factory,
+      ServiceWorkerSingleScriptUpdateChecker::ResultCallback callback) {
+    auto fetch_client_settings_object =
+        blink::mojom::FetchClientSettingsObject::New(
+            []() {
+              auto policies = blink::mojom::PolicyContainerPolicies::New();
+              policies->referrer_policy =
+                  network::mojom::ReferrerPolicy::kDefault;
+              return policies;
+            }(),
+            GURL(url), blink::mojom::InsecureRequestsPolicy::kDoNotUpgrade);
+    return std::make_unique<ServiceWorkerSingleScriptUpdateChecker>(
+        GURL(url), /*is_main_script=*/true, GURL(url), scope,
+        /*force_bypass_cache=*/false, blink::mojom::ScriptType::kClassic,
+        blink::mojom::ServiceWorkerUpdateViaCache::kNone,
+        std::move(fetch_client_settings_object),
+        /*time_since_last_check=*/base::TimeDelta(), browser_context_.get(),
+        base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+            loader_factory),
+        WrapReader(std::move(compare_reader)),
+        WrapReader(std::move(copy_reader)), std::move(writer),
+        /*writer_resource_id=*/0,
+        ServiceWorkerSingleScriptUpdateChecker::ScriptChecksumUpdateOption::
+            kDefault,
+        blink::StorageKey::Create(url::Origin::Create(scope),
+                                  net::SchemefulSite(scope),
+                                  blink::mojom::AncestorChainBit::kSameSite,
+                                  /*third_party_partitioning_allowed=*/true),
+        /*network_restrictions_id=*/std::nullopt, PolicyContainerPolicies(),
+        std::move(callback));
+  }
+
   mojo::Remote<storage::mojom::ServiceWorkerResourceWriter> WrapWriter(
       std::unique_ptr<MockServiceWorkerResourceWriter> writer) {
     mojo::Remote<storage::mojom::ServiceWorkerResourceWriter> remote;
@@ -1450,6 +1490,58 @@
   }
 }
 
+// Tests that the checker can be safely destroyed from inside its result
+// callback when writing the response headers to storage fails synchronously
+// (e.g., the storage writer connection has gone away).
+TEST_F(ServiceWorkerSingleScriptUpdateCheckerTest,
+       DestroyedInCallbackOnSynchronousHeaderWriteFailure) {
+  auto loader_factory = std::make_unique<network::TestURLLoaderFactory>();
+  auto compare_reader = std::make_unique<MockServiceWorkerResourceReader>();
+  auto copy_reader = std::make_unique<MockServiceWorkerResourceReader>();
+
+  mojo::Remote<storage::mojom::ServiceWorkerResourceWriter> writer_remote;
+  auto writer_receiver = writer_remote.BindNewPipeAndPassReceiver();
+
+  std::unique_ptr<ServiceWorkerSingleScriptUpdateChecker> checker;
+  std::optional<ServiceWorkerSingleScriptUpdateChecker::Result> result;
+  checker = CreateSingleScriptUpdateCheckerWithCallback(
+      kScriptURL, GURL(kScope), std::move(compare_reader),
+      std::move(copy_reader), std::move(writer_remote), loader_factory.get(),
+      base::BindLambdaForTesting(
+          [&](const GURL&,
+              ServiceWorkerSingleScriptUpdateChecker::Result compare_result,
+              std::unique_ptr<
+                  ServiceWorkerSingleScriptUpdateChecker::FailureInfo>,
+              std::unique_ptr<
+                  ServiceWorkerSingleScriptUpdateChecker::PausedState>,
+              const std::optional<std::string>&) {
+            result = compare_result;
+            // The owner may destroy the checker synchronously in response to
+            // the result.
+            checker.reset();
+          }));
+
+  // Disconnect the storage writer before the network response arrives so that
+  // writing headers fails synchronously.
+  writer_receiver.reset();
+  checker->FlushRemotesForTesting();
+  ASSERT_FALSE(result.has_value());
+
+  auto head = network::mojom::URLResponseHead::New();
+  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+      net::HttpUtil::AssembleRawHeaders(kSuccessHeader));
+  head->headers->GetMimeType(&head->mime_type);
+  head->parsed_headers = network::mojom::ParsedHeaders::New();
+  loader_factory->SimulateResponseForPendingRequest(
+      GURL(kScriptURL), network::URLLoaderCompletionStatus(net::OK),
+      std::move(head), "abcdef");
+  ASSERT_TRUE(base::test::RunUntil([&]() { return result.has_value(); }));
+
+  EXPECT_EQ(result.value(),
+            ServiceWorkerSingleScriptUpdateChecker::Result::kFailed);
+  EXPECT_FALSE(checker);
+}
+
 class ServiceWorkerSingleScriptUpdateCheckerSha256ChecksumTest
     : public ServiceWorkerSingleScriptUpdateCheckerTest,
       public testing::WithParamInterface<
Loading diff…

Original Bug Report

reported by [email protected]

Potential Use-After-Free in ServiceWorkerSingleScriptUpdateChecker

Flapjack, 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. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.

Overview: A Use-After-Free vulnerability exists in the browser process when handling Service Worker script updates. If the connection to the storage process is disconnected, a synchronous callback chain can delete the ServiceWorkerSingleScriptUpdateChecker object while a method is still executing on the stack, leading to memory corruption when control unwinds.

Affected files:

  • content/browser/service_worker/service_worker_single_script_update_checker.cc

Estimated timestamp from git blame: 2022-01-25

Description

A potential Use-After-Free (UAF) vulnerability exists in content::ServiceWorkerSingleScriptUpdateChecker::OnReceiveResponse within the browser process. The issue stems from the fact that ServiceWorkerCacheWriter::MaybeWriteHeaders can invoke its completion callback synchronously if an immediate error occurs, such as the Mojo connection to the storage process being disconnected.

This synchronous error handling initiates a callback chain that ultimately destroys the ServiceWorkerSingleScriptUpdateChecker instance. When the call stack unwinds, execution continues in OnReceiveResponse using a dangling this pointer to write to member variables and invoke further methods.

Suggested Exploitation Steps

(Note: These are suggested steps based on code analysis; a working Proof of Concept has not been run.)

  1. An attacker registers a Service Worker on a controlled origin and triggers an update for it.
  2. The browser creates a ServiceWorkerUpdateChecker, which in turn creates a ServiceWorkerSingleScriptUpdateChecker and stores it in a std::unique_ptr.
  3. The update checker initiates a network request for the updated script.
  4. Before the network headers arrive, the attacker induces a condition that causes the Mojo pipe to the Storage process to disconnect (e.g., by exhausting resources to crash the storage process).
  5. When the network response headers arrive, ServiceWorkerSingleScriptUpdateChecker::OnReceiveResponse is called.
  6. OnReceiveResponse processes the headers and synchronously calls WriteHeaders(), passing a callback bound with a WeakPtr.
  7. WriteHeaders() calls ServiceWorkerCacheWriter::MaybeWriteHeaders().
  8. Because the storage pipe is disconnected, MaybeWriteHeaders() synchronously executes the callback with net::ERR_FAILED.
  9. The callback invokes ServiceWorkerSingleScriptUpdateChecker::OnWriteHeadersComplete(), which calls Fail(), and then Finish().
  10. Finish() synchronously executes its stored callback_, signaling failure back to ServiceWorkerUpdateChecker::OnOneUpdateCheckFinished().
  11. If this is the main script, the failure is propagated to ServiceWorkerRegisterJob::OnUpdateCheckFinished(), which synchronously aborts the job via Complete(), resulting in the destruction of the ServiceWorkerUpdateChecker and its std::unique_ptr<ServiceWorkerSingleScriptUpdateChecker>.
  12. The object is freed, and the stack unwinds back to OnReceiveResponse() immediately after the WriteHeaders() call.
  13. Execution continues using the dangling this pointer. The method performs several operations on the freed memory, including network_consumer_ = std::move(consumer); and modifying network_loader_state_. This corrupts the freed memory chunk with predictable/attacker-controlled values.
  14. Finally, it calls MaybeStartNetworkConsumerHandleWatcher(), which interacts with the corrupted network_watcher_ member, potentially leading to arbitrary code execution in the unsandboxed browser process.

Impact

This is a critical vulnerability because it occurs in the unsandboxed browser process. Successful exploitation of this memory corruption could lead to arbitrary Remote Code Execution (RCE) and a full sandbox escape. Note that MiraclePtr (BackupRefPtr) does not protect against this specific UAF because the dangling pointer is the implicit this pointer stored on the stack, not a heap-to-heap pointer.

Suggested Fix

There are a few ways to mitigate this:

  1. Asynchronous Callbacks: Ensure that ServiceWorkerCacheWriter::MaybeWriteHeaders (and similar methods) always invoke their completion callbacks asynchronously, even for immediate errors. This prevents synchronous destruction while methods are still on the stack.
  2. WeakPtr Checks: If synchronous callbacks are permitted, ServiceWorkerSingleScriptUpdateChecker::OnReceiveResponse must check if this is still valid after calling WriteHeaders(). This can be achieved by creating a WeakPtr to this before the call and checking it immediately after the call returns. If the WeakPtr has been invalidated, the method should return immediately.

Evaluated with Chrome root at commit: 2155cb00003ec35716a76ed3246eae995f87b7ff


Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:

  • If you are familiar with the severity guidelines, you may adjust the severity.
  • If this is a false positive, and there’s no work to be done, please close as WAI.
  • If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.

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.

View on issue tracker