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 <[email protected]> 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. [email protected] Bug: 40058068 Change-Id: I680e759afda3c582d38c05fb98e322065c43f124 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6464959 Reviewed-by: Min Qin <[email protected]> Commit-Queue: Peter Beverloo <[email protected]> Reviewed-by: Peter Beverloo <[email protected]> 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 <[email protected]> Matthieu Vlad Hauglustaine <[email protected]> Mattias Buelens <[email protected]> +Maurice Dauer <[email protected]> Max Coplan <[email protected]> Max Perepelitsyn <[email protected]> Max Schmitt <[email protected]> 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