Chrome · DeviceBoundSessionCredentials
CVE-2026-87449
Logic Error in DeviceBoundSessionCredentials
Overview
Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Files Changed
net/device_bound_sessions/registration_fetcher.cc
Patch
From 6dce8e75d9b25edc36726a8b58ac63b81bfe8a13 Mon Sep 17 00:00:00 2001
From: Ali Hijazi <ahijazi@chromium.org>
Date: Sat, 15 Aug 2026 08:55:16 -0700
Subject: [PATCH] [DBSC] Enforce Fetch-Metadata and secure redirects
Network fetches for Device Bound Session Credentials (DBSC) bypass the
network::URLLoader, which ordinarily injects standard W3C Fetch-Metadata
headers. Without explicit metadata decoration, outgoing Discovery,
Registration, and Refresh requests lacked `Origin`, `Sec-Fetch-Mode`,
`Sec-Fetch-Dest`, and `Sec-Fetch-Site` assertions. Furthermore,
`URLFetcher`'s redirect handling previously allowed unvalidated HTTP 3xx
protocol downgrades (exposing DBSC cryptographic tokens and session
cookies to plaintext leakage) and failed to synchronize `Sec-Fetch-Site`
metadata upon traversing same-site or cross-origin redirect boundaries.
- Installs W3C Resource-Isolation headers (`no-cors`, `empty`,
`Origin`, and `Sec-Fetch-Site`) across all Discovery and
Registration/Refresh pipelines.
- Implements rigorous redirect defenses in `URLFetcher::OnReceivedRedirect`:
* Aborts plaintext (HTTP) protocol-downgrade transitions via
`net::ERR_UNSAFE_REDIRECT`, neutralizing token-leakage risks.
* Dynamically re-calculates and mutates `Sec-Fetch-Site` header
values at each redirect hop relative to the baseline `referring_origin`.
Bug: 501850947
Change-Id: I8a2ea35547d58567f9551e2557b61fcd2951cfef
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8139249
Reviewed-by: Adam Rice <ricea@chromium.org>
Commit-Queue: Ali Hijazi <ahijazi@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1680192}
---
diff --git a/net/device_bound_sessions/registration_fetcher.cc b/net/device_bound_sessions/registration_fetcher.cc
index efe2d49..1ad0ee2 100644
--- a/net/device_bound_sessions/registration_fetcher.cc
+++ b/net/device_bound_sessions/registration_fetcher.cc
@@ -16,6 +16,7 @@
#include "base/functional/callback_helpers.h"
#include "base/functional/concurrent_closures.h"
#include "base/metrics/histogram_functions.h"
+#include "base/notreached.h"
#include "base/rand_util.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
@@ -27,6 +28,7 @@
#include "net/base/features.h"
#include "net/base/net_errors.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "net/base/url_util.h"
#include "net/device_bound_sessions/registration_request_param.h"
#include "net/device_bound_sessions/session_binding_utils.h"
#include "net/device_bound_sessions/session_challenge_param.h"
@@ -35,6 +37,7 @@
#include "net/device_bound_sessions/session_key.h"
#include "net/device_bound_sessions/session_params.h"
#include "net/device_bound_sessions/url_fetcher.h"
+#include "net/http/http_request_headers.h"
#include "net/log/net_log_event_type.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/url_request_context.h"
@@ -205,6 +208,7 @@
public:
RegistrationFetcherImpl(
const GURL& fetcher_endpoint,
+ url::Origin referring_origin,
std::optional<std::string> session_identifier,
SessionService& session_service,
unexportable_keys::UnexportableKeyService& key_service,
@@ -215,6 +219,7 @@
const std::optional<url::Origin>& original_request_initiator,
unexportable_keys::BackgroundTaskPriority priority)
: fetcher_endpoint_(fetcher_endpoint),
+ referring_origin_(std::move(referring_origin)),
session_identifier_(std::move(session_identifier)),
session_service_(session_service),
key_service_(key_service),
@@ -374,13 +379,9 @@
// TODO(crbug.com/495096658): Assert that `IsForRefreshRequest()` is false
// once the tests are fixed.
url_fetcher_ = std::make_unique<URLFetcher>(
- context_, well_known_url, net_log_source_, IsForRefreshRequest());
- url_fetcher_->request().set_method("GET");
- url_fetcher_->request().set_disallow_credentials();
- url_fetcher_->request().set_site_for_cookies(
- isolation_info_.site_for_cookies());
- url_fetcher_->request().set_initiator(original_request_initiator_);
- url_fetcher_->request().set_isolation_info(isolation_info_);
+ context_, well_known_url, referring_origin_, net_log_source_,
+ IsForRefreshRequest());
+ ConfigureWellKnownRequest(url_fetcher_->request());
url_fetcher_->Start(base::BindOnce(
&RegistrationFetcherImpl::OnProviderWellKnownRequestComplete,
GetWeakPtr(), request_params.TakeChallenge(),
@@ -409,9 +410,40 @@
}
private:
+ // Consolidates common URLRequest initialization, credential isolation, and
+ // W3C Resource-Isolation 'no-cors'/'empty' Fetch-Metadata parameters utilized
+ // uniformly across both Discovery (GET) and Registration (POST) DBSC
+ // operations.
+ // TODO(crbug.com/546625323): Stop duplicating request header and
+ // Fetch-Metadata population logic, and explore offloading header construction
+ // to `SessionService` or reusing `//services/network/sec_header_helpers.h`.
+ void SetupCommonFetchMetadata(URLRequest& request) {
+ request.set_site_for_cookies(site_for_cookies_);
+ request.set_initiator(original_request_initiator_);
+ request.set_isolation_info(isolation_info_);
+
+ request.SetExtraRequestHeaderByName(kSecFetchModeHeaderName, "no-cors",
+ /*overwrite=*/true);
+ request.SetExtraRequestHeaderByName(kSecFetchDestHeaderName, "empty",
+ /*overwrite=*/true);
+ request.SetExtraRequestHeaderByName(
+ kSecFetchSiteHeaderName,
+ SecFetchSiteForReferringOrigin(referring_origin_, request.url()),
+ /*overwrite=*/true);
+ }
+
+ // Configures and decorates an outbound `.well-known` DBSC discovery
+ // URLRequest via a side-effect-free, credentialless HTTP GET operation.
+ void ConfigureWellKnownRequest(URLRequest& request) {
+ request.set_method("GET");
+ request.set_disallow_credentials();
+ SetupCommonFetchMetadata(request);
+ }
+
void StartFetcherEndpointRequest() {
url_fetcher_ = std::make_unique<URLFetcher>(
- context_, fetcher_endpoint_, net_log_source_, IsForRefreshRequest());
+ context_, fetcher_endpoint_, referring_origin_, net_log_source_,
+ IsForRefreshRequest());
ConfigureRequest(url_fetcher_->request());
if (last_registration_token_.has_value()) {
url_fetcher_->request().SetExtraRequestHeaderByName(
@@ -438,13 +470,9 @@
replacements.SetPathStr("/.well-known/device-bound-sessions");
GURL well_known_url = fetcher_endpoint_.ReplaceComponents(replacements);
url_fetcher_ = std::make_unique<URLFetcher>(
- context_, well_known_url, net_log_source_, IsForRefreshRequest());
- url_fetcher_->request().set_method("GET");
- url_fetcher_->request().set_disallow_credentials();
- url_fetcher_->request().set_site_for_cookies(
- isolation_info_.site_for_cookies());
- url_fetcher_->request().set_initiator(original_request_initiator_);
- url_fetcher_->request().set_isolation_info(isolation_info_);
+ context_, well_known_url, referring_origin_, net_log_source_,
+ IsForRefreshRequest());
+ ConfigureWellKnownRequest(url_fetcher_->request());
url_fetcher_->Start(base::BindOnce(
&RegistrationFetcherImpl::OnRelyingPartyWellKnownRequestComplete,
GetWeakPtr(), std::move(challenge), std::move(authorization)));
@@ -624,9 +652,17 @@
request.set_method("POST");
request.SetLoadFlags(LOAD_DISABLE_CACHE);
- request.set_site_for_cookies(site_for_cookies_);
- request.set_initiator(original_request_initiator_);
- request.set_isolation_info(isolation_info_);
+ // Apply baseline W3C Fetch-Metadata ('no-cors', 'empty', 'Sec-Fetch-Site')
+ // and isolation boundaries utilized across all DBSC request pipelines.
+ SetupCommonFetchMetadata(request);
+
+ // The endpoint may be a different (same-site) origin from the response or
+ // session that configured it, so attach `Origin` and Fetch Metadata
+ // headers reflecting that relationship. These requests don't go through
+ // `network::URLLoader`, which would otherwise add them.
+ request.SetExtraRequestHeaderByName(HttpRequestHeaders::kOrigin,
+ referring_origin_.Serialize(),
+ /*overwrite=*/true);
if (IsForRefreshRequest()) {
request.SetExtraRequestHeaderByName(
@@ -808,13 +844,9 @@
GURL well_known_url =
fetcher_endpoint_.ReplaceComponents(std::move(replacements));
url_fetcher_ = std::make_unique<URLFetcher>(
- context_, well_known_url, net_log_source_, /*is_refresh=*/false);
- url_fetcher_->request().set_method("GET");
- url_fetcher_->request().set_disallow_credentials();
- url_fetcher_->request().set_site_for_cookies(
- isolation_info_.site_for_cookies());
- url_fetcher_->request().set_initiator(original_request_initiator_);
- url_fetcher_->request().set_isolation_info(isolation_info_);
+ context_, well_known_url, referring_origin_, net_log_source_,
+ /*is_refresh=*/false);
+ ConfigureWellKnownRequest(url_fetcher_->request());
url_fetcher_->Start(base::BindOnce(
&RegistrationFetcherImpl::
OnSubdomainRegistrationWellKnownRequestComplete,
@@ -927,6 +959,10 @@
// Refers to the endpoint this class will use when triggering a registration
// or refresh request.
GURL fetcher_endpoint_;
+ // The origin that configured `fetcher_endpoint_`: the origin of the response
+ // carrying the registration header, or the scope origin of the session being
+ // refreshed.
+ url::Origin referring_origin_;
// Populated iff this is a refresh request (not a registration request).
std::optional<std::string> session_identifier_;
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/net/device_bound_sessions/registration_fetcher_param_unittest.cc b/net/device_bound_sessions/registration_fetcher_param_unittest.cc
index 5e21cb3..ddc297c 100644
--- a/net/device_bound_sessions/registration_fetcher_param_unittest.cc
+++ b/net/device_bound_sessions/registration_fetcher_param_unittest.cc
@@ -64,6 +64,8 @@
const auto& param = params[0];
EXPECT_EQ(param.registration_endpoint(),
GURL("https://www.example.com/startsession"));
+ EXPECT_EQ(param.referring_origin(),
+ url::Origin::Create(registration_request));
EXPECT_THAT(param.supported_algos(),
UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
EXPECT_EQ(param.challenge(), "c1");
@@ -471,6 +473,8 @@
const auto& param = params[0];
EXPECT_EQ(param.registration_endpoint(),
GURL("https://accounts.example.com/startsession"));
+ EXPECT_EQ(param.referring_origin(),
+ url::Origin::Create(registration_request));
EXPECT_THAT(param.supported_algos(),
UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
EXPECT_EQ(param.challenge(), "c1");
diff --git a/net/device_bound_sessions/registration_fetcher_unittest.cc b/net/device_bound_sessions/registration_fetcher_unittest.cc
index f053118..314ad00f 100644
--- a/net/device_bound_sessions/registration_fetcher_unittest.cc
+++ b/net/device_bound_sessions/registration_fetcher_unittest.cc
@@ -72,11 +72,13 @@
using ::base::test::ValueIs;
using ::testing::_;
using ::testing::AllOf;
+using ::testing::Contains;
using ::testing::ElementsAre;
using ::testing::Eq;
using ::testing::Invoke;
using ::testing::Not;
using ::testing::Optional;
+using ::testing::Pair;
using ::testing::Property;
using ::testing::Return;
using ::testing::WithArg;
@@ -211,7 +213,6 @@
context_ = context_builder->Build();
}
-
unexportable_keys::UnexportableKeyService& unexportable_key_service() {
return unexportable_key_service_;
}
@@ -1941,6 +1942,123 @@
"auth_cookie", "Domain=.a.test; Path=/; Secure; SameSite=None")));
}
+std::unique_ptr<test_server::HttpResponse> CaptureFetchMetadataHeaders(
+ test_server::HttpRequest::HeaderMap* out_headers,
+ const test_server::HttpRequest& request) {
+ for (const char* name :
+ {"Origin", "Sec-Fetch-Site", "Sec-Fetch-Mode", "Sec-Fetch-Dest"}) {
+ auto it = request.headers.find(name);
+ if (it != request.headers.end()) {
+ (*out_headers)[name] = it->second;
+ }
+ }
+ return ReturnResponse(HTTP_OK, kBasicValidJson, request);
+}
+
+TEST_F(RegistrationTest, RefreshSendsOriginAndFetchMetadata) {
+ crypto::ScopedFakeUnexportableKeyProvider scoped_fake_key_provider;
+ test_server::HttpRequest::HeaderMap received_headers;
+ server_.RegisterRequestHandler(base::BindRepeating(
+ &CaptureFetchMetadataHeaders, base::Unretained(&received_headers)));
+ ASSERT_TRUE(server_.Start());
+
+ TestRegistrationCallback callback;
+ auto isolation_info = IsolationInfo::CreateTransient(/*nonce=*/std::nullopt);
+ auto request_param = RegistrationRequestParam::CreateForTesting(
+ GetBaseURL(), kSessionIdentifier, kChallenge,
+ /*authorization=*/std::nullopt);
+ UnexportableSigningKeyId key = CreateSigningKey();
+ std::unique_ptr<RegistrationFetcher> fetcher =
+ RegistrationFetcher::CreateFetcher(
+ request_param, session_service(),
+ std::ref(unexportable_key_service()), context_.get(),
+ std::ref(isolation_info), net::SiteForCookies(),
+ /*net_log_source=*/std::nullopt,
+ /*original_request_initiator=*/std::nullopt,
+ unexportable_keys::BackgroundTaskPriority::kBestEffort);
+ fetcher->StartFetchWithExistingKey(request_param, std::move(key),
+ callback.callback());
+ callback.WaitForCall();
+ callback.outcome().SessionForTesting();
+
+ EXPECT_THAT(
+ received_headers,
+ Contains(Pair("Origin", url::Origin::Create(GetBaseURL()).Serialize())));
+ EXPECT_THAT(received_headers,
+ Contains(Pair("Sec-Fetch-Site", "same-origin")));
+ EXPECT_THAT(received_headers, Contains(Pair("Sec-Fetch-Mode", "no-cors")));
+ EXPECT_THAT(received_headers, Contains(Pair("Sec-Fetch-Dest", "empty")));
+}
+
+TEST_F(RegistrationTest, RefreshSendsSameSiteFetchMetadataForCrossOrigin) {
+ crypto::ScopedFakeUnexportableKeyProvider scoped_fake_key_provider;
+ test_server::HttpRequest::HeaderMap received_headers;
+ server_.RegisterRequestHandler(base::BindRepeating(
+ &CaptureFetchMetadataHeaders, base::Unretained(&received_headers)));
+ ASSERT_TRUE(server_.Start());
+
+ // The session is scoped to a sibling origin within the same site as the
+ // refresh endpoint.
+ url::Origin scope_origin =
+ url::Origin::Create(server_.GetURL("other.a.test", "/"));
+
+ TestRegistrationCallback callback;
+ auto isolation_info = IsolationInfo::CreateTransient(/*nonce=*/std::nullopt);
+ auto request_param = RegistrationRequestParam::CreateForTesting(
+ GetBaseURL(), kSessionIdentifier, kChallenge,
+ /*authorization=*/std::nullopt, AttestationMode::kNone, scope_origin);
+ UnexportableSigningKeyId key = CreateSigningKey();
+ std::unique_ptr<RegistrationFetcher> fetcher =
+ RegistrationFetcher::CreateFetcher(
+ request_param, session_service(),
+ std::ref(unexportable_key_service()), context_.get(),
+ std::ref(isolation_info), net::SiteForCookies(),
+ /*net_log_source=*/std::nullopt,
+ /*original_request_initiator=*/std::nullopt,
+ unexportable_keys::BackgroundTaskPriority::kBestEffort);
+ fetcher->StartFetchWithExistingKey(request_param, std::move(key),
+ callback.callback());
+ callback.WaitForCall();
+ callback.outcome().SessionForTesting();
+
+ EXPECT_THAT(received_headers,
+ Contains(Pair("Origin", scope_origin.Serialize())));
+ EXPECT_THAT(received_headers, Contains(Pair("Sec-Fetch-Site", "same-site")));
+ EXPECT_THAT(received_headers, Contains(Pair("Sec-Fetch-Mode", "no-cors")));
+ EXPECT_THAT(received_headers, Contains(Pair("Sec-Fetch-Dest", "empty")));
+}
+
+TEST_F(RegistrationTest, RegistrationSendsOriginAndFetchMetadata) {
+ crypto::ScopedFakeUnexportableKeyProvider scoped_fake_key_provider;
+ test_server::HttpRequest::HeaderMap received_headers;
+ server_.RegisterRequestHandler(base::BindRepeating(
+ &CaptureFetchMetadataHeaders, base::Unretained(&received_headers)));
+ ASSERT_TRUE(server_.Start());
+
+ TestRegistrationCallback callback;
+ auto param = GetBasicParam();
+ std::unique_ptr<RegistrationFetcher> fetcher =
+ RegistrationFetcher::CreateFetcher(
+ param, session_service(), unexportable_key_service(), context_.get(),
+ IsolationInfo::CreateTransient(/*nonce=*/std::nullopt),
+ net::SiteForCookies(),
+ /*net_log_source=*/std::nullopt,
+ /*original_request_initiator=*/std::nullopt,
+ unexportable_keys::BackgroundTaskPriority::kBestEffort);
+ fetcher->StartCreateTokenAndFetch(param, CreateAlgArray(),
+ callback.callback());
+ callback.WaitForCall();
+ callback.outcome().SessionForTesting();
+
+ EXPECT_THAT(
+ received_headers,
+ Contains(Pair("Origin", url::Origin::Create(GetBaseURL()).Serialize())));
+ EXPECT_THAT(received_headers,
+ Contains(Pair("Sec-Fetch-Site", "same-origin")));
+ EXPECT_THAT(received_headers, Contains(Pair("Sec-Fetch-Mode", "no-cors")));
+ EXPECT_THAT(received_headers, Contains(Pair("Sec-Fetch-Dest", "empty")));
+}
+
TEST_F(RegistrationTest, FetchRegistrationAndChallengeRequired) {
crypto::ScopedFakeUnexportableKeyProvider scoped_fake_key_provider;
server_.RegisterRequestHandler(base::BindRepeating(&ReturnForbidden));
@@ -3038,6 +3156,93 @@
SessionError::kSubdomainRegistrationWellKnownUnavailable);
}
+TEST_F(RegistrationTest, FederatedWellKnownDiscoverySendsFetchMetadata) {
+ crypto::ScopedFakeUnexportableKeyProvider scoped_fake_key_provider;
+
+ test_server::HttpRequest::HeaderMap captured_headers;
+ bool well_known_fetched = false;
+
+ // 1. Initial Endpoint Response: Instruct the Fetcher to redirect onto a
+ // Subdomain scope, implicitly triggering the DBSC cross-origin .well-known
+ // verification pipeline.
+ server_.RegisterRequestHandler(base::BindLambdaForTesting(
+ [&](const test_server::HttpRequest& request)
+ -> std::unique_ptr<test_server::HttpResponse> {
+ if (request.relative_url != "/") {
+ return nullptr;
+ }
+ auto response = std::make_unique<test_server::BasicHttpResponse>();
+ response->set_code(HTTP_FOUND);
+ response->AddCustomHeader(
+ "Location", server_.GetURL("subdomain.a.test", "/dbsc").spec());
+ return response;
+ }));
+
+ // 2. Mock Config Delivery for the Subdomain path.
+ server_.RegisterRequestHandler(base::BindLambdaForTesting(
+ [&](const test_server::HttpRequest& request)
+ -> std::unique_ptr<test_server::HttpResponse> {
+ if (request.relative_url != "/dbsc") {
+ return nullptr;
+ }
+ return ReturnResponse(HTTP_OK, kBasicValidJson, request);
+ }));
+
+ // 3. .well-known Interceptor: Capture the outbound GET metadata for the
+ // cross-origin validation check.
+ server_.RegisterRequestHandler(base::BindLambdaForTesting(
+ [&](const test_server::HttpRequest& request)
+ -> std::unique_ptr<test_server::HttpResponse> {
+ if (request.relative_url != "/.well-known/device-bound-sessions") {
+ return nullptr;
+ }
+
+ for (const char* name :
+ {"Sec-Fetch-Site", "Sec-Fetch-Mode", "Sec-Fetch-Dest"}) {
+ auto it = request.headers.find(name);
+ if (it != request.headers.end()) {
+ captured_headers[name] = it->second;
+ }
+ }
+
+ well_known_fetched = true;
+ // Yield a 404 to cleanly isolate the test strictly to the pre-flight
+ // discovery dispatch.
+ return ReturnResponse(HTTP_NOT_FOUND, "", request);
+ }));
+
+ ASSERT_TRUE(server_.Start());
+
+ GURL registration_url = server_.GetURL("a.test", "/");
+ TestRegistrationCallback callback;
+
+ // Trigger Subdomain Cross-Origin Registration, implicitly firing the
+ // .well-known discovery step on the server-bound origin.
+ auto param = GetBasicParam(registration_url);
+ std::unique_ptr<RegistrationFetcher> fetcher =
+ RegistrationFetcher::CreateFetcher(
+ param, session_service(), unexportable_key_service(), context_.get(),
+ IsolationInfo::CreateTransient(/*nonce=*/std::nullopt),
+ net::SiteForCookies(),
+ /*net_log_source=*/std::nullopt,
+ /*original_request_initiator=*/std::nullopt,
+ unexportable_keys::BackgroundTaskPriority::kBestEffort);
+ fetcher->StartCreateTokenAndFetch(param, CreateAlgArray(),
+ callback.callback());
+ callback.WaitForCall();
+
+ // 1. Assert the .well-known validator was indeed engaged by the DBSC
+ // state-machine.
+ EXPECT_TRUE(well_known_fetched);
+
+ // 2. Validate that our ConfigureWellKnownRequest pipeline successfully
+ // computed and appended W3C 'no-cors', 'empty', and Origin-relative Metadata.
+ EXPECT_THAT(captured_headers, Contains(Pair("Sec-Fetch-Mode", "no-cors")));
+ EXPECT_THAT(captured_headers, Contains(Pair("Sec-Fetch-Dest", "empty")));
+ EXPECT_THAT(captured_headers,
+ Contains(Pair("Sec-Fetch-Site", "same-origin")));
+}
+
TEST_F(RegistrationTest, FederatedSuccess) {
crypto::ScopedFakeUnexportableKeyProvider scoped_fake_key_provider;
diff --git a/net/device_bound_sessions/session_binding_utils_unittest.cc b/net/device_bound_sessions/session_binding_utils_unittest.cc
index b2a982f..a88c193 100644
--- a/net/device_bound_sessions/session_binding_utils_unittest.cc
+++ b/net/device_bound_sessions/session_binding_utils_unittest.cc
@@ -22,6 +22,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
+#include "url/origin.h"
namespace net::device_bound_sessions {
@@ -336,4 +337,37 @@
std::nullopt);
}
+TEST(SessionBindingUtilsTest, SecFetchSiteForReferringOrigin) {
+ // Validate that W3C Sec-Fetch-Site string-literal translation correctly
+ // resolves 'same-origin', 'same-site', and 'cross-site' origin relationships,
+ // including strictness against unencrypted/HTTP protocol-mismatches.
+ url::Origin referring_origin =
+ url::Origin::Create(GURL("https://www.example.com"));
+
+ // 1. Same-Origin: Matching cryptographic scheme, eTLD+1, and subdomain.
+ EXPECT_EQ(
+ SecFetchSiteForReferringOrigin(
+ referring_origin, GURL("https://www.example.com/path/to/resource")),
+ "same-origin");
+
+ // 2. Same-Site: Matching cryptographic scheme and eTLD+1, but differing
+ // subdomain boundaries.
+ EXPECT_EQ(
+ SecFetchSiteForReferringOrigin(
+ referring_origin, GURL("https://subdomain.example.com/endpoint")),
+ "same-site");
... (truncated)
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