CVE-2026-7968
Overview
Files Changed
services/network/cors/cors_url_loader.ccservices/network/public/cpp/features.ccservices/network/public/cpp/features.h
Patch
From 583163b3b6df95304e03dcb3a7d97f191d38072b Mon Sep 17 00:00:00 2001 From: Takashi Toyoshima <[email protected]> Date: Fri, 07 Aug 2026 06:27:25 -0700 Subject: [PATCH] Remove network::features::kIgnoreCorsPreflightPolicy Remove the expired feature flag kIgnoreCorsPreflightPolicy and its usage in CorsURLLoader::NeedsPreflight. Change-Id: Ia05b681fe92123d16022b20c34820037bbf72654 Bug: 497432281 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8214839 Reviewed-by: Adam Rice <[email protected]> Commit-Queue: Takashi Toyoshima <[email protected]> Cr-Commit-Position: refs/heads/main@{#1675666} --- diff --git a/services/network/cors/cors_url_loader.cc b/services/network/cors/cors_url_loader.cc index 1ff2b5d..7d31e958 100644 --- a/services/network/cors/cors_url_loader.cc +++ b/services/network/cors/cors_url_loader.cc @@ -94,12 +94,6 @@ return PreflightRequiredReason::kCorsWithForcedPreflightMode; } - if (!base::FeatureList::IsEnabled(features::kIgnoreCorsPreflightPolicy) && - request.cors_preflight_policy == - mojom::CorsPreflightPolicy::kPreventPreflight) { - return std::nullopt; - } - if (!IsCorsSafelistedMethod(request.method)) return PreflightRequiredReason::kDisallowedMethod; diff --git a/services/network/public/cpp/features.cc b/services/network/public/cpp/features.cc index b6c7b01..b65d81c 100644 --- a/services/network/public/cpp/features.cc +++ b/services/network/public/cpp/features.cc @@ -197,9 +197,6 @@ // and continue the handshake without sending one if requested. BASE_FEATURE(kOmitCorsClientCert, base::FEATURE_DISABLED_BY_DEFAULT); -// Ignore CorsPreflightPolicy and always perform CORS checks. -BASE_FEATURE(kIgnoreCorsPreflightPolicy, base::FEATURE_ENABLED_BY_DEFAULT); - // Enforces that frame-type destinations require kNavigate mode. BASE_FEATURE(kRestrictFrameDestinationsToNavigate, base::FEATURE_ENABLED_BY_DEFAULT); diff --git a/services/network/public/cpp/features.h b/services/network/public/cpp/features.h index f1698cc3..432ae312 100644 --- a/services/network/public/cpp/features.h +++ b/services/network/public/cpp/features.h @@ -81,9 +81,6 @@ BASE_DECLARE_FEATURE(kOmitCorsClientCert); COMPONENT_EXPORT(NETWORK_CPP_FLAGS_AND_SWITCHES) -BASE_DECLARE_FEATURE(kIgnoreCorsPreflightPolicy); - -COMPONENT_EXPORT(NETWORK_CPP_FLAGS_AND_SWITCHES) BASE_DECLARE_FEATURE(kRestrictFrameDestinationsToNavigate); COMPONENT_EXPORT(NETWORK_CPP_FLAGS_AND_SWITCHES)
Original Bug Report
CORS preflight bypass via renderer-controlled cors_preflight_policy
Project Fortify, an experimental security project, has identified the following potential security issue.
Overview: A compromised renderer can bypass Out-of-Renderer CORS (OOR-CORS) preflights by manipulating the cors_preflight_policy Mojo field. This allows attackers to send credentialed cross-origin requests with non-simple methods (e.g., DELETE) or headers without the mandatory OPTIONS preflight. This exposes cross-origin servers to state-changing CSRF attacks.
Affected files:
services/network/cors/cors_url_loader.ccservices/network/cors/cors_url_loader_factory.ccservices/network/public/mojom/url_request.mojom
Estimated timestamp from git blame: 2026-02-01
Description
There is a potential Out-of-Renderer CORS (OOR-CORS) bypass caused by missing validation of the cors_preflight_policy field when receiving a ResourceRequest from an untrusted renderer process.
The network::mojom::URLRequest Mojo struct includes a cors_preflight_policy field. When an untrusted renderer sends a request via URLLoaderFactory::CreateLoaderAndStart, the Network Service evaluates the request using CorsURLLoaderFactory::IsValidRequest() (in services/network/cors/cors_url_loader_factory.cc). While this function performs extensive validation on fields like load_flags and request_initiator, it completely ignores cors_preflight_policy.
Because this field is not sanitized, a compromised renderer can set it to mojom::CorsPreflightPolicy::kPreventPreflight. Later, when CorsURLLoader::NeedsPreflight() (in services/network/cors/cors_url_loader.cc) is called to determine if an OPTIONS preflight is necessary, it explicitly checks this field:
std::optional<PreflightRequiredReason> NeedsPreflight(
const ResourceRequest& request) {
// ...
if (request.cors_preflight_policy ==
mojom::CorsPreflightPolicy::kPreventPreflight) {
return std::nullopt;
}
// ... checks for IsCorsSafelistedMethod and CorsUnsafeNotForbiddenRequestHeaderNames
}
Returning std::nullopt forces the Network Service to skip the preflight check entirely. This allows an attacker to send credentialed cross-origin requests with non-safelisted methods (e.g., DELETE, PUT) or custom headers without triggering the CORS preflight, leading to CSRF vulnerabilities against APIs that rely on CORS preflight enforcement.
Potential Steps to Trigger
Note: Our tooling agent cannot run code, so these are suggested theoretical steps to exploit the vulnerability.
- Compromise Renderer: An attacker compromises a renderer process, gaining the ability to craft raw Mojo messages.
- Craft Request: The attacker uses their Mojo access to construct a
network::mojom::URLRequesttargeting a cross-origin state-changing endpoint (e.g.,https://target.com/api/delete-account). - Set Non-Simple Attributes: The attacker sets the HTTP
methodtoDELETEand setscredentials_modetokIncludeto send the victim’s ambient cookies. - Exploit the Policy Field: The attacker sets the
cors_preflight_policyfield tokPreventPreflight(enum value1). - Send the Request: The attacker sends the IPC via the
URLLoaderFactory::CreateLoaderAndStartendpoint provided to the renderer. - Bypass Preflight: The Network Service (
CorsURLLoaderFactory) accepts the request becauseIsValidRequestmisses this field.CorsURLLoaderseeskPreventPreflight, skips the OPTIONS request, and directly sends theDELETErequest with cookies to the target server. - CSRF Execution: The target server receives the
DELETErequest and processes it, assuming it was authorized by a successful preflight, resulting in a successful Cross-Site Request Forgery.
Suggested Fix
In CorsURLLoaderFactory::IsValidRequest() (services/network/cors/cors_url_loader_factory.cc), add a check to restrict cors_preflight_policy for untrusted callers. For example:
if (!is_trusted_) {
if (request.cors_preflight_policy != mojom::CorsPreflightPolicy::kConsiderPreflight) {
mojo::ReportBadMessage(
"CorsURLLoaderFactory: Untrusted caller attempting to bypass CORS preflight");
return false;
}
// ... existing checks ...
}
Alternatively, force the field to kConsiderPreflight for all requests originating from untrusted renderers.
Evaluated with Chrome root at commit: a9cbf6e8b275fe4147435aa905f3b7f5a656f5f0
Results from so far have been promising, but there can be wrong deductions. If this proves to be a false positive, please close as WAI; 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.