CVE-2025-5064
Overview
Background
- Background Fetch API
- a web API that lets a page/service worker schedule resource fetches that continue in the background via the browser’s download service rather than as normal page-driven network requests.
- `request_initiator`
- the origin that initiated a network request, documented in
url_request.mojom, which the network stack relies on to perform security checks (e.g. same-origin, site-isolation, and CORS-related decisions). - `DownloadParams` / `download_url_params`
- the parameter structs threaded from the background-fetch delegate through the download service (
components/download/...) to build the actual network download request. - `isolation_info`
- the network isolation key information already passed through this path; the patch adds the initiator origin alongside it.
Root Cause Analysis
Background Fetch scheduled its requests through the download service, but the download path never populated a request initiator, so the resulting network requests lacked the request_initiator that url_request.mojom says is required for certain security checks. In components/download/public/background_service/download_params.h there was no field to carry the origin, so components/background_fetch/background_fetch_delegate_base.cc could not forward it and components/download/content/internal/download_driver_impl.cc never set it on download_url_params. Because these background-fetch requests behaved like ordinary downloads (which normally do not need an initiator), the origin-dependent checks could be skipped or misapplied — the “inappropriate implementation in Background Fetch API” the advisory describes.
The fix adds a std::optional<url::Origin> initiator field to DownloadParams, sets params.request_params.initiator = job_details->fetch_description->origin in the background-fetch delegate, and, in the download driver, calls download_url_params->set_initiator(request_params.initiator.value()) when the initiator is present, so the initiating origin flows to the network request and the required security checks run with correct context.
request_initiator-based security checks lacked their input; the fix threads fetch_description->origin into DownloadParams::initiator and sets it as the request initiator before the download is issued.Attack Path
- Issue a background fetch A page or service worker uses the Background Fetch API to schedule a request that is routed to the download service.
- Request built without initiator
Pre-patch,
download_driver_impl.ccconstructeddownload_url_paramswithout setting an initiator becauseDownloadParamshad noinitiatorfield to carry the origin. - Security checks lack context
The network request proceeds without a
request_initiator, so origin-dependent checks thaturl_request.mojomrequires are not applied as they would be for a page-initiated fetch. - Policy bypass The attacker’s background fetch reaches resources or is treated in ways that the initiating origin’s security checks should have constrained. (inferred specific cross-origin access primitive)
Impact Assessment
request_initiator, consistent with the advisory’s “Inappropriate implementation in Background Fetch API.” The precondition is the ability to use the Background Fetch API from a page/service worker. The vendor advisory rates this medium severity and does not report in-the-wild exploitation; NVD scores it CVSS 5.4. Any concrete escalation such as cross-origin data access beyond the missing-initiator condition is (inferred).Changed Functions
| Function | Change | Notes |
|---|---|---|
ifcomponents/download/content/internal/download_driver_impl.cc |
modified |
Files Changed
AUTHORScomponents/background_fetch/background_fetch_delegate_base.cccomponents/download/content/internal/download_driver_impl.cccomponents/download/public/background_service/download_params.h
Audit Directions
- Requests routed around the normal network pathAudit APIs (background fetch, downloads, prefetch, service-worker-scheduled fetches) that build network requests through non-standard paths and verify
request_initiatorand isolation info are set as they are for page-driven requests. - Optional security fields left unsetLook for
std::optionalsecurity-relevant fields (initiator, isolation info, trusted params) that are only conditionally set, and confirm callers on privileged paths always populate them. - `url_request.mojom` invariantsCross-check consumers of
url_request.mojomrequest parameters against its documented requirements to find code that satisfies functional needs but omits the fields the security checks depend on.
Patch
From 43cac9d509983c7f68a5ffa119cc7509bde375ea Mon Sep 17 00:00:00 2001
From: Maurice Dauer <layton.cscg@gmail.com>
Date: Tue, 22 Apr 2025 02:49:18 -0700
Subject: [PATCH] [Background fetch] Pass request initiator to download service
The request initiator is required to perform certain security checks,
see |request_initiator| in url_request.mojom for details. Since
background fetch doesn't work like a normal download, we need to pass it
to the download service.
R=peter@chromium.org
Bug: 40058068
Change-Id: I680e759afda3c582d38c05fb98e322065c43f124
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6464959
Reviewed-by: Min Qin <qinmin@chromium.org>
Commit-Queue: Peter Beverloo <peter@chromium.org>
Reviewed-by: Peter Beverloo <peter@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1449821}
---
diff --git a/AUTHORS b/AUTHORS
index cb106a2..3dc5d32b 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -975,6 +975,7 @@
Matthieu Rigolot <matthieu.rigolot@gmail.com>
Matthieu Vlad Hauglustaine <matt.hauglustaine@gmail.com>
Mattias Buelens <mattias.buelens@gmail.com>
+Maurice Dauer <layton.cscg@gmail.com>
Max Coplan <mchcopl@gmail.com>
Max Perepelitsyn <pph34r@gmail.com>
Max Schmitt <max@schmitt.mx>
diff --git a/components/background_fetch/background_fetch_delegate_base.cc b/components/background_fetch/background_fetch_delegate_base.cc
index 2cd4b82..d4ecd4e5 100644
--- a/components/background_fetch/background_fetch_delegate_base.cc
+++ b/components/background_fetch/background_fetch_delegate_base.cc
@@ -114,6 +114,7 @@
job_details->MarkJobAsStarted();
}
+ params.request_params.initiator = job_details->fetch_description->origin;
params.request_params.isolation_info =
job_details->fetch_description->isolation_info;
diff --git a/components/download/content/internal/download_driver_impl.cc b/components/download/content/internal/download_driver_impl.cc
index 0428af02..5e0f726 100644
--- a/components/download/content/internal/download_driver_impl.cc
+++ b/components/download/content/internal/download_driver_impl.cc
@@ -229,6 +229,9 @@
}
download_url_params->set_update_first_party_url_on_redirect(
request_params.update_first_party_url_on_redirect);
+ if (request_params.initiator) {
+ download_url_params->set_initiator(request_params.initiator.value());
+ }
download_manager_coordinator_->DownloadUrl(std::move(download_url_params));
}
diff --git a/components/download/public/background_service/download_params.h b/components/download/public/background_service/download_params.h
index 8d539cb..5277fcc 100644
--- a/components/download/public/background_service/download_params.h
+++ b/components/download/public/background_service/download_params.h
@@ -18,6 +18,7 @@
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "services/network/public/mojom/fetch_api.mojom-shared.h"
#include "url/gurl.h"
+#include "url/origin.h"
namespace download {
@@ -135,6 +136,13 @@
// considered a main frame navigation. However, this is not true for
// background fetch.
bool update_first_party_url_on_redirect = true;
+
+ // The origin that initiated the request. This is used to perform
+ // security checks. Normally, these checks aren't required for downloads,
+ // but necessary for background fetch.
+ // See |request_initiator| in url_request.mojom for a more detailed
+ // explanation.
+ std::optional<url::Origin> initiator;
};
// The parameters that describe a download request made to the DownloadService.
Original Bug Report
Security: Bypass of Issue 1239709: Cross-Origin Response Leak If wildcard ACAO is sent
VULNERABILITY DETAILS
BackgroundFetch sends cookies even if the credentials mode is “omit” or “same-origin” and thus bypassing the fix for https://crbug.com/chromium/1239709.
VERSION
Version 96.0.4664.45 (Official Build) Arch Linux (64-bit)
REPRODUCTION CASE
Using the glitch.me site from https://crbug.com/chromium/1239709:
- Set a cookie at https://echo-cookie-test.glitch.me
<script>
const url = "https://echo-cookie-test.glitch.me/echo-cookie"; // some site with a wildcard ACAO header
navigator.serviceWorker.ready.then(async (swReg) => {
// { credentials: "same-origin" || "omit" } still sends cookies, but isn't blocked
const bgFetch = await swReg.backgroundFetch.fetch("test", [new Request(url, { credentials: "omit" })]);
const targetPage = await bgFetch.match(url);
const response = await targetPage.responseReady;
console.log(await response.text()); // response contains cookie
});
navigator.serviceWorker.register("sw.js");
</script>
// can be empty
I’m not entirely sure, but AFAIU setting the request->request_initiator1, that is explained here2, in the DownloadParams struct, that is declared here3, should fix this.
Also not sure how that relates to https://crbug.com/chromium/1268580 and if that fixes it too.
CREDIT INFORMATION
Reporter credit: Maurice Dauer
- https://crbug.com/chromium/1239709
- https://crbug.com/chromium/1268580
- https://echo-cookie-test.glitch.me
- https://echo-cookie-test.glitch.me/echo-cookie
- https://source.chromium.org/chromium/chromium/src/+/main:components/background_fetch/background_fetch_delegate_base.cc;l=93
- https://source.chromium.org/chromium/chromium/src/+/main:components/download/internal/common/download_utils.cc;l=277
- https://source.chromium.org/chromium/chromium/src/+/main:net/url_request/url_request.h;l=328