CVE-2026-6313
Overview
Background
- `no-cors` request mode
- A fetch mode (
mojom::RequestMode::kNoCors) that permits cross-origin requests with opaque responses and a restricted header/method surface, used for things like<img>,<script>, andfetch(..., {mode:'no-cors'}). - Forbidden method
- HTTP methods the Fetch spec bars scripts from issuing (
CONNECT,TRACE,TRACK), tested bycors::IsForbiddenMethod, because they enable connection hijacking or cross-site tracing attacks. - `CorsURLLoaderFactory`
- The network-service component that validates each request (
IsValidRequest) before it is dispatched and callsmojo::ReportBadMessageon an invalid one. - `IsForbiddenMethod` / `kConnectMethod`
- Helper that matches the forbidden-method set, and the constant for the
CONNECTmethod name used in the old special case.
Root Cause Analysis
In CorsURLLoaderFactory::IsValidRequest (named in the commit message; the enclosing function is not shown in the @@ header), the old guard only rejected a forbidden method when the request mode was not kNoCors, and in the kNoCors case rejected only CONNECT. The removed comment states this directly: forbidden methods were disallowed “for any requests except RequestMode::kNoCors,” with only CONNECT unconditionally blocked. This left TRACE and TRACK permitted whenever a request used no-cors mode, violating the Fetch invariant that forbidden methods must never be issued by web content regardless of mode.
The fix replaces the entire compound condition with a single if (cors::IsForbiddenMethod(request.method)), so all three forbidden methods are blocked in every mode before the request proceeds. This is a tightening of the check: the no-cors exemption for TRACE/TRACK is removed, as confirmed by the unit test flipping TRACE and TRACK from expect_allowed_for_no_cors = true to false.
no-cors-mode exception that allowed the forbidden methods TRACE and TRACK; the fix deletes the exception and blocks any forbidden method unconditionally.Attack Path
- Issue a no-cors request
Page script initiates a cross-origin request in
no-corsmode (e.g.fetch(url, {mode:'no-cors', method:'TRACE'})). Ground: the removed condition only special-cased thekNoCorsbranch. - Bypass the forbidden-method filter
Because the method is
TRACEorTRACKand the mode iskNoCors, the old guard’s second clause matched onlyCONNECT, soIsValidRequestreturned without callingReportBadMessageand the request was accepted. Ground: the pre-patch condition and the test rows{"TRACE", true}/{"TRACK", true}. - Send the forbidden method cross-origin
The network service dispatches a cross-origin
TRACE/TRACKthat the Fetch policy was supposed to forbid, enabling cross-site tracing behavior (inferred: potential for reflecting headers/cookies via the server’s trace echo).
Impact Assessment
TRACE/TRACK requests that the Fetch standard forbids, by selecting no-cors mode to evade the method filter in the network service. The advisory rates this High severity with impact “Insufficient policy enforcement in CORS”; it does not report in-the-wild exploitation. Any concrete escalation (e.g. Cross-Site Tracing / header reflection against a vulnerable server) depends on server behavior and is (inferred); the patch itself only demonstrates that the methods were wrongly permitted.Changed Functions
| Function | Change | Notes |
|---|---|---|
forservices/network/cors/cors_url_loader_unittest.cc |
modified |
Files Changed
services/network/cors/cors_url_loader_factory.ccservices/network/cors/cors_url_loader_unittest.cc
Audit Directions
- Mode-conditional security checksFlag any policy check gated on
RequestMode(especiallykNoCorsexemptions); verify the relaxation is spec-justified rather than an accidental hole. - Partial allow/deny listsLook for filters that special-case one element of a forbidden set (here only
CONNECT) while silently permitting the rest; confirm the full set (cors::IsForbiddenMethod) is enforced. - Network-service request validationReview other
IsValidRequest-style gates inservices/networkfor methods, headers, or schemes that are validated differently across request modes.
Patch
From d513cd2fe6684b38bc02c3df59bfc5183bf4e1fd Mon Sep 17 00:00:00 2001 From: Kenichi Ishibashi <[email protected]> Date: Fri, 10 Apr 2026 17:14:24 -0700 Subject: [PATCH] [CORS] Block forbidden methods for no-cors requests Previously, forbidden methods like TRACE and TRACK were allowed when the request mode was no-cors, and only CONNECT was unconditionally blocked. This CL updates CorsURLLoaderFactory::IsValidRequest to block all forbidden methods regardless of the request mode. The unit test is also updated to reflect this new restriction. Bug: 498765210 Change-Id: Ie451a3c2b8fa7aafdebade8b3ba517be3ce255f8 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7743444 Reviewed-by: mmenke <[email protected]> Commit-Queue: Kenichi Ishibashi <[email protected]> Cr-Commit-Position: refs/heads/main@{#1613186} --- diff --git a/services/network/cors/cors_url_loader_factory.cc b/services/network/cors/cors_url_loader_factory.cc index 6a1eb07..bf02d66 100644 --- a/services/network/cors/cors_url_loader_factory.cc +++ b/services/network/cors/cors_url_loader_factory.cc @@ -910,13 +910,8 @@ return false; } - // Don't allow forbidden methods for any requests except RequestMode::kNoCors. - // Don't allow CONNECT method for any request. - if ((request.mode != mojom::RequestMode::kNoCors && - cors::IsForbiddenMethod(request.method)) || - (request.mode == mojom::RequestMode::kNoCors && - base::EqualsCaseInsensitiveASCII( - request.method, net::HttpRequestHeaders::kConnectMethod))) { + // Don't allow forbidden methods. + if (cors::IsForbiddenMethod(request.method)) { mojo::ReportBadMessage("CorsURLLoaderFactory: Forbidden method"); return false; } diff --git a/services/network/cors/cors_url_loader_unittest.cc b/services/network/cors/cors_url_loader_unittest.cc index e9bbbc2..23a9e809 100644 --- a/services/network/cors/cors_url_loader_unittest.cc +++ b/services/network/cors/cors_url_loader_unittest.cc @@ -109,11 +109,10 @@ std::string forbidden_method; bool expect_allowed_for_no_cors; } kTestCases[] = { - // CONNECT is never allowed, while TRACE and TRACK are allowed only with - // RequestMode::kNoCors. + // CONNECT, TRACE and TRACK are not allowed for any mode. {"CONNECT", false}, - {"TRACE", true}, - {"TRACK", true}, + {"TRACE", false}, + {"TRACK", false}, }; for (const auto& test_case : kTestCases) { SCOPED_TRACE(test_case.forbidden_method);
Regression Test / PoC
diff --git a/services/network/cors/cors_url_loader_unittest.cc b/services/network/cors/cors_url_loader_unittest.cc
index e9bbbc2..23a9e809 100644
--- a/services/network/cors/cors_url_loader_unittest.cc
+++ b/services/network/cors/cors_url_loader_unittest.cc
@@ -109,11 +109,10 @@
std::string forbidden_method;
bool expect_allowed_for_no_cors;
} kTestCases[] = {
- // CONNECT is never allowed, while TRACE and TRACK are allowed only with
- // RequestMode::kNoCors.
+ // CONNECT, TRACE and TRACK are not allowed for any mode.
{"CONNECT", false},
- {"TRACE", true},
- {"TRACK", true},
+ {"TRACE", false},
+ {"TRACK", false},
};
for (const auto& test_case : kTestCases) {
SCOPED_TRACE(test_case.forbidden_method);
Original Bug Report
Bypass of Site Isolation via TRACE method in kNoCors mode
Project Fortify, 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 without the security team.
Overview: A logic flaw in the Network Service allows a compromised renderer to bypass forbidden HTTP method checks by sending a TRACE request in kNoCors mode. This causes cross-origin SameSite=None cookies to be reflected back in the response body, which is not blocked by Opaque Response Blocking (ORB), leading to cross-origin data exfiltration.
Affected files:
services/network/cors/cors_url_loader_factory.ccservices/network/orb/orb_impl.ccservices/network/public/cpp/cors/cors.ccservices/network/orb/orb_mimetypes.cc
Estimated timestamp from git blame: 2022-02-08
Summary
A compromised renderer process can potentially exfiltrate cross-origin SameSite=None and HttpOnly cookies from any target origin that has the HTTP TRACE method enabled. This is possible due to a gap between CORS validation and Opaque Response Blocking (ORB) in the Network Service. Specifically, CorsURLLoaderFactory allows the TRACE method for requests marked with kNoCors mode, and ORB defaults to failing-open for the resulting message/http reflected response.
Vulnerability Details
1. CORS Method Validation Bypass
In Blink, the Fetch API explicitly forbids methods like TRACE (third_party/blink/renderer/core/fetch/request.cc). However, a compromised renderer can bypass Blink’s checks by directly constructing and sending a network::ResourceRequest via the network::mojom::URLLoaderFactory Mojo interface.
When the Network Service receives this request, CorsURLLoaderFactory::IsValidRequest validates it. While it normally blocks forbidden methods, there is an exception for kNoCors mode:
// services/network/cors/cors_url_loader_factory.cc:913
if ((request.mode != mojom::RequestMode::kNoCors &&
cors::IsForbiddenMethod(request.method)) ||
(request.mode == mojom::RequestMode::kNoCors &&
base::EqualsCaseInsensitiveASCII(
request.method, net::HttpRequestHeaders::kConnectMethod))) {
mojo::ReportBadMessage("CorsURLLoaderFactory: Forbidden method");
return false;
}
By setting request.mode = kNoCors, the attacker bypasses the IsForbiddenMethod check. TRACE is allowed through, and because it is kNoCors, no CORS preflight is required.
2. Credential Attachment and TRACE Reflection
If the attacker also sets request.credentials_mode = kInclude, the network stack attaches the target cross-origin server’s SameSite=None cookies to the outgoing TRACE request. (Note: SameSite=Lax/Strict cookies are protected because the request is cross-site).
The HTTP TRACE method specification requires the server to echo the received request back to the client, typically with a Content-Type: message/http. This means the SameSite=None cookies are reflected in the response body.
3. ORB Fail-Open for message/http
Because the request is a cross-origin kNoCors request, the response is routed through Opaque Response Blocking (ORB).
- MIME Type: ORB categorizes
message/httpasMimeType::kOthers. - Sniffing: The response body starts with the reflected request line (e.g.,
"TRACE / HTTP/1.1"). This does not match the blocklisted signatures for HTML, XML, or JSON, causingSniffto returnDecision::kSniffMore. - Fail-Open Decision: Once sniffing concludes,
OpaqueResponseBlockingAnalyzer::HandleEndOfSniffableResponseBodydefaults to a fail-open state, returningDecision::kAllow.
Because ORB allows the response, the original Mojo data pipe containing the full response body (with the reflected cookies) is forwarded back to the compromised renderer, allowing the attacker to read them.
Potential Reproduction Steps
Note: These are suggested steps for a proof-of-concept, as our analysis is based on static code review.
- From a compromised renderer process, obtain a
network::mojom::URLLoaderFactoryremote (e.g., the default subresource loader factory). - Call
CreateLoaderAndStartwith anetwork::ResourceRequestconfigured as follows:url:https://target-with-trace-enabled.com/method:TRACEmode:kNoCorscredentials_mode:kInclude
- Capture the response using a
network::mojom::URLLoaderClient. - Read the raw response data pipe to extract the reflected request headers, including the victim’s cross-origin cookies.
Recommended Fix
Update CorsURLLoaderFactory::IsValidRequest to block all forbidden methods regardless of the RequestMode. The exception for kNoCors is unnecessary since the web platform (Fetch/XHR) does not allow TRACE or TRACK to be used even in no-cors mode.
if (cors::IsForbiddenMethod(request.method) ||
base::EqualsCaseInsensitiveASCII(
request.method, net::HttpRequestHeaders::kConnectMethod)) {
mojo::ReportBadMessage("CorsURLLoaderFactory: Forbidden method");
return false;
}
Evaluated with Chrome root at commit: ff3d2b74fa39431785bd60e51463b08fcc71ee33
Results 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.