Chrome · BackgroundFetch
CVE-2026-87453
Logic Error in BackgroundFetch
Overview
Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
forcontent/browser/background_fetch/background_fetch_service_impl.cc |
modified | |
ifcontent/browser/background_fetch/background_fetch_service_impl.cc |
modified | |
TEST_Fcontent/browser/background_fetch/background_fetch_service_unittest.cc |
modified |
Files Changed
content/browser/background_fetch/background_fetch_service_impl.cccontent/browser/background_fetch/background_fetch_service_unittest.cc
Patch
From 8046f4cc56ed8aebe6c9aa4838f5ae6b1ba07764 Mon Sep 17 00:00:00 2001
From: Nidhi Jaju <nidhijaju@chromium.org>
Date: Fri, 07 Aug 2026 04:08:03 -0700
Subject: [PATCH] [BackgroundFetch] Validate request URL scheme in the browser
BackgroundFetchManager in the renderer rejects request URLs that do not
use a HTTP(S) scheme. Mirror that check in
BackgroundFetchServiceImpl::ValidateRequests() so the browser process
does not forward such requests to the download subsystem, which would
otherwise treat them as trusted browser requests.
Bug: 495444970
Change-Id: If25e925d5d7e19a9d53453971933dc0d10d9a4a1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8200209
Commit-Queue: Peter Beverloo <peter@chromium.org>
Auto-Submit: Nidhi Jaju <nidhijaju@chromium.org>
Reviewed-by: Peter Beverloo <peter@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1675631}
---
diff --git a/content/browser/background_fetch/background_fetch_service_impl.cc b/content/browser/background_fetch/background_fetch_service_impl.cc
index f2e3d9f..97f0ba9 100644
--- a/content/browser/background_fetch/background_fetch_service_impl.cc
+++ b/content/browser/background_fetch/background_fetch_service_impl.cc
@@ -222,6 +222,24 @@
return false;
}
+ // Ensure all requests are valid and use the HTTP or HTTPS scheme.
+ for (const auto& request : requests) {
+ if (!request) {
+ mojo::ReportBadMessage("Null request");
+ return false;
+ }
+
+ if (!request->url.is_valid()) {
+ mojo::ReportBadMessage("Invalid request URL");
+ return false;
+ }
+
+ if (!request->url.SchemeIsHTTPOrHTTPS()) {
+ mojo::ReportBadMessage("Invalid request URL scheme");
+ return false;
+ }
+ }
+
return true;
}
diff --git a/content/browser/background_fetch/background_fetch_service_unittest.cc b/content/browser/background_fetch/background_fetch_service_unittest.cc
index 287e7ec5..9fb5ec3a 100644
--- a/content/browser/background_fetch/background_fetch_service_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_service_unittest.cc
@@ -493,11 +493,69 @@
blink::mojom::BackgroundFetchRegistrationPtr registration;
Fetch(/* service_worker_registration_id= */ 42, kExampleDeveloperId,
- std::move(requests), std::move(options), SkBitmap(), &error,
+ std::move(requests), options.Clone(), SkBitmap(), &error,
®istration);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ARGUMENT);
EXPECT_EQ("Invalid requests", bad_message_observer.WaitForBadMessage());
}
+
+ // Request URLs must use the HTTP or HTTPS scheme.
+ {
+ mojo::FakeMessageDispatchContext fake_dispatch_context;
+ mojo::test::BadMessageObserver bad_message_observer;
+ std::vector<blink::mojom::FetchAPIRequestPtr> requests;
+ auto request = CreateRequestWithProvidedResponse(
+ "GET", GURL("file:///test.txt"),
+ TestResponseBuilder(200).MakeIndefinitelyPending().Build());
+ requests.push_back(std::move(request));
+
+ blink::mojom::BackgroundFetchError error;
+ blink::mojom::BackgroundFetchRegistrationPtr registration;
+
+ Fetch(/* service_worker_registration_id= */ 42, kExampleDeveloperId,
+ std::move(requests), options.Clone(), SkBitmap(), &error,
+ ®istration);
+ EXPECT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ARGUMENT);
+ EXPECT_EQ("Invalid request URL scheme",
+ bad_message_observer.WaitForBadMessage());
+ }
+
+ // Request URLs must be valid URLs.
+ {
+ mojo::FakeMessageDispatchContext fake_dispatch_context;
+ mojo::test::BadMessageObserver bad_message_observer;
+ std::vector<blink::mojom::FetchAPIRequestPtr> requests;
+ auto request = CreateRequestWithProvidedResponse(
+ "GET", GURL("invalid-url"),
+ TestResponseBuilder(200).MakeIndefinitelyPending().Build());
+ requests.push_back(std::move(request));
+
+ blink::mojom::BackgroundFetchError error;
+ blink::mojom::BackgroundFetchRegistrationPtr registration;
+
+ Fetch(/* service_worker_registration_id= */ 42, kExampleDeveloperId,
+ std::move(requests), options.Clone(), SkBitmap(), &error,
+ ®istration);
+ EXPECT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ARGUMENT);
+ EXPECT_EQ("Invalid request URL", bad_message_observer.WaitForBadMessage());
+ }
+
+ // Request objects in the vector must be non-null.
+ {
+ mojo::FakeMessageDispatchContext fake_dispatch_context;
+ mojo::test::BadMessageObserver bad_message_observer;
+ std::vector<blink::mojom::FetchAPIRequestPtr> requests;
+ requests.push_back(nullptr);
+
+ blink::mojom::BackgroundFetchError error;
+ blink::mojom::BackgroundFetchRegistrationPtr registration;
+
+ Fetch(/* service_worker_registration_id= */ 42, kExampleDeveloperId,
+ std::move(requests), std::move(options), SkBitmap(), &error,
+ ®istration);
+ EXPECT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ARGUMENT);
+ EXPECT_EQ("Null request", bad_message_observer.WaitForBadMessage());
+ }
}
TEST_F(BackgroundFetchServiceTest, FetchRegistrationProperties) {
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/content/browser/background_fetch/background_fetch_service_unittest.cc b/content/browser/background_fetch/background_fetch_service_unittest.cc
index 287e7ec5..9fb5ec3a 100644
--- a/content/browser/background_fetch/background_fetch_service_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_service_unittest.cc
@@ -493,11 +493,69 @@
blink::mojom::BackgroundFetchRegistrationPtr registration;
Fetch(/* service_worker_registration_id= */ 42, kExampleDeveloperId,
- std::move(requests), std::move(options), SkBitmap(), &error,
+ std::move(requests), options.Clone(), SkBitmap(), &error,
®istration);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ARGUMENT);
EXPECT_EQ("Invalid requests", bad_message_observer.WaitForBadMessage());
}
+
+ // Request URLs must use the HTTP or HTTPS scheme.
+ {
+ mojo::FakeMessageDispatchContext fake_dispatch_context;
+ mojo::test::BadMessageObserver bad_message_observer;
+ std::vector<blink::mojom::FetchAPIRequestPtr> requests;
+ auto request = CreateRequestWithProvidedResponse(
+ "GET", GURL("file:///test.txt"),
+ TestResponseBuilder(200).MakeIndefinitelyPending().Build());
+ requests.push_back(std::move(request));
+
+ blink::mojom::BackgroundFetchError error;
+ blink::mojom::BackgroundFetchRegistrationPtr registration;
+
+ Fetch(/* service_worker_registration_id= */ 42, kExampleDeveloperId,
+ std::move(requests), options.Clone(), SkBitmap(), &error,
+ ®istration);
+ EXPECT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ARGUMENT);
+ EXPECT_EQ("Invalid request URL scheme",
+ bad_message_observer.WaitForBadMessage());
+ }
+
+ // Request URLs must be valid URLs.
+ {
+ mojo::FakeMessageDispatchContext fake_dispatch_context;
+ mojo::test::BadMessageObserver bad_message_observer;
+ std::vector<blink::mojom::FetchAPIRequestPtr> requests;
+ auto request = CreateRequestWithProvidedResponse(
+ "GET", GURL("invalid-url"),
+ TestResponseBuilder(200).MakeIndefinitelyPending().Build());
+ requests.push_back(std::move(request));
+
+ blink::mojom::BackgroundFetchError error;
+ blink::mojom::BackgroundFetchRegistrationPtr registration;
+
+ Fetch(/* service_worker_registration_id= */ 42, kExampleDeveloperId,
+ std::move(requests), options.Clone(), SkBitmap(), &error,
+ ®istration);
+ EXPECT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ARGUMENT);
+ EXPECT_EQ("Invalid request URL", bad_message_observer.WaitForBadMessage());
+ }
+
+ // Request objects in the vector must be non-null.
+ {
+ mojo::FakeMessageDispatchContext fake_dispatch_context;
+ mojo::test::BadMessageObserver bad_message_observer;
+ std::vector<blink::mojom::FetchAPIRequestPtr> requests;
+ requests.push_back(nullptr);
+
+ blink::mojom::BackgroundFetchError error;
+ blink::mojom::BackgroundFetchRegistrationPtr registration;
+
+ Fetch(/* service_worker_registration_id= */ 42, kExampleDeveloperId,
+ std::move(requests), std::move(options), SkBitmap(), &error,
+ ®istration);
+ EXPECT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_ARGUMENT);
+ EXPECT_EQ("Null request", bad_message_observer.WaitForBadMessage());
+ }
}
TEST_F(BackgroundFetchServiceTest, FetchRegistrationProperties) {
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.
References
On This Page