Medium watch CVSS 5.9 chrome Info Disclosure 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
5.9
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInformation leak in SignIn
DescriptionInformation leak in SignIn
ComponentSignIn
Sub-componentGoogle_apis
Bug ClassInfo Disclosure
Action tierwatch — information disclosure — security-relevant, below the RCE-class bar
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Tracker513608831
Fix commit49bb74f7f158 (chromium/src) +109/-2
CWECWE-200 (Information exposure)
CVSS vectorCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N
CISA KEVNot listed
CreditedGoogle
Reported2026-05-15 (per vendor advisory)
Fix landed2026-07-31 (public git)
Disclosed2026-08-25
Patch gap25 days — fix public in source before the advisory

Background

`UrlFetchRequestBase`
The base class in google_apis that builds outgoing Google API requests, attaches an Authorization header carrying the user’s OAuth access token, and drives them via SimpleURLLoader.
`SimpleURLLoader`
A network-service client helper that, by default, forwards explicitly configured request headers (including Authorization) across HTTP redirects unless a redirect callback removes them.
Redirect callback (`SetOnRedirectCallback`)
A hook invoked on each 3xx redirect that receives the pre- and post-redirect URLs and a mutable to_be_removed_headers list, letting the caller strip headers before the request is re-sent to the new location.
Same-origin check (`url::IsSameOriginWith`)
Compares scheme/host/port of two URLs; a mismatch means the redirect target is a different origin and should not receive credentials scoped to the original origin.

Root Cause Analysis

UrlFetchRequestBase set the Authorization header as an explicitly configured header and executed the request through SimpleURLLoader, which forwards such headers across redirects by default and had no redirect callback registered. Consequently, when a Google API endpoint returned a 3xx redirect to a different origin, SimpleURLLoader re-sent the request to that origin with the OAuth access token still attached, leaking the credential to a third-party destination. The invariant violated is that an origin-scoped bearer token must never be transmitted to a different origin.

The fix registers UrlFetchRequestBase::OnRedirect via SetOnRedirectCallback, which compares url_before_redirect with redirect_info.new_url using url::IsSameOriginWith and, on a cross-origin redirect, appends net::HttpRequestHeaders::kAuthorization to to_be_removed_headers; same-origin redirects leave the header intact to preserve existing workflows. The regression tests confirm the header reaches the primary origin’s /redirect and /target but is absent on the cross-origin server, while a same-origin redirect retains it on both hops.

Key insight
The single mistake was relying on SimpleURLLoader’s default header-forwarding across redirects without a redirect callback, so an origin-scoped Authorization token followed cross-origin 3xx redirects; the fix adds an OnRedirect handler that strips the header whenever the redirect target is not same-origin.

Attack Path

  1. Attacker controls or influences a redirecting endpoint An API request built by UrlFetchRequestBase targets a URL that responds with a 3xx redirect whose Location points to an attacker-controlled cross-origin destination. (inferred)
  2. Redirect forwarded with credentials Pre-patch, with no redirect callback registered, SimpleURLLoader re-issues the request to the new origin and forwards the explicitly configured Authorization header unchanged.
  3. Token delivered cross-origin The attacker’s server receives the request bearing the victim’s OAuth access token in the Authorization header, capturing the credential.
  4. Credential misuse With the leaked access token the attacker can impersonate the user against Google APIs within the token’s scope. (inferred)

Impact Assessment

An attacker able to make a Google API request redirect to an origin they control can capture the user’s OAuth access token, an information-disclosure flaw affecting requests issued through google_apis in the browser process. The vendor advisory rates this medium severity and does not report in-the-wild exploitation; NVD scores it CVSS 5.9. (inferred) The precondition is a cross-origin 3xx redirect on a request that carries the Authorization header.

Changed Functions

FunctionChangeNotes
Value
google_apis/common/base_requests.h
modified
RequestSender
google_apis/common/base_requests.h
modified
TEST_F
google_apis/common/base_requests_unittest.cc
modified
TEST
google_apis/common/base_requests_unittest.cc
modified

Files Changed

  • google_apis/common/base_requests.cc
  • google_apis/common/base_requests_unittest.cc
  • google_apis/common/base_requests.h

Audit Directions

  • `SimpleURLLoader` users attaching credentials
    Audit all callers that set Authorization or other secret headers on a SimpleURLLoader/ResourceRequest and verify each registers a redirect callback that drops them on cross-origin (or all) redirects.
  • Default cross-redirect header forwarding
    Search for network requests that add sensitive headers without SetOnRedirectCallback, since the default behavior forwards explicitly configured headers to redirect targets.
  • Same-origin vs same-site scoping
    Review credential-stripping predicates to confirm they use IsSameOriginWith (scheme+host+port) rather than a looser same-site or host-only comparison that could still leak to a different port/scheme.
From 49bb74f7f1589143f800972535ff296ad9dae6b9 Mon Sep 17 00:00:00 2001
From: Ming-Ying Chung <[email protected]>
Date: Fri, 31 Jul 2026 00:28:10 -0700
Subject: [PATCH] [google_apis] Drop Authorization header on cross-origin redirects

`UrlFetchRequestBase` attaches an `Authorization` header to outgoing
Google API requests and executes them through `SimpleURLLoader`.
`SimpleURLLoader` forwards explicitly configured headers across HTTP
redirects. Consequently, if an API endpoint responds with a 3xx redirect
to a different origin, the access token is forwarded to the redirected
destination.

To prevent credential leakage, register a redirect callback on
`SimpleURLLoader` that checks if the redirect target is same-origin with
the previous URL. Cross-origin redirects append the `Authorization`
header to the list of headers to remove, while same-origin redirects
retain the header for existing workflows.

Bug: 513608831
Change-Id: I6b19f963c9ff3bb0b996b1fe29bbbe84d962d18e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8050627
Commit-Queue: Ming-Ying Chung <[email protected]>
Reviewed-by: Eriko Kurimoto <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1671672}
---
diff --git a/google_apis/common/base_requests.cc b/google_apis/common/base_requests.cc
index 037901c..6268c47 100644
--- a/google_apis/common/base_requests.cc
+++ b/google_apis/common/base_requests.cc
@@ -30,8 +30,10 @@
 #include "net/http/http_request_headers.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_util.h"
+#include "net/url_request/redirect_info.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/mojom/url_response_head.mojom.h"
+#include "url/origin.h"
 
 #if BUILDFLAG(IS_POSIX)
 #include <fcntl.h>
@@ -308,9 +310,24 @@
   url_loader_->SetOnResponseStartedCallback(base::BindOnce(
       &UrlFetchRequestBase::OnResponseStarted, weak_ptr_factory_.GetWeakPtr()));
 
+  url_loader_->SetOnRedirectCallback(base::BindRepeating(
+      &UrlFetchRequestBase::OnRedirect, weak_ptr_factory_.GetWeakPtr()));
+
   url_loader_->DownloadAsStream(sender_->url_loader_factory(), this);
 }
 
+void UrlFetchRequestBase::OnRedirect(
+    const GURL& url_before_redirect,
+    const net::RedirectInfo& redirect_info,
+    const network::mojom::URLResponseHead& response_head,
+    std::vector<std::string>* to_be_removed_headers) {
+  // Strip the Authorization header on cross-origin redirects to prevent
+  // sensitive access tokens from leaking to third-party destinations.
+  if (!url::IsSameOriginWith(url_before_redirect, redirect_info.new_url)) {
+    to_be_removed_headers->push_back(net::HttpRequestHeaders::kAuthorization);
+  }
+}
+
 void UrlFetchRequestBase::OnDownloadProgress(ProgressCallback progress_callback,
                                              uint64_t current) {
   progress_callback.Run(static_cast<int64_t>(current),
diff --git a/google_apis/common/base_requests.h b/google_apis/common/base_requests.h
index 7e0dda0..605a72a 100644
--- a/google_apis/common/base_requests.h
+++ b/google_apis/common/base_requests.h
@@ -32,6 +32,10 @@
 class Value;
 }  // namespace base
 
+namespace net {
+struct RedirectInfo;
+}  // namespace net
+
 namespace google_apis {
 
 class RequestSender;
@@ -258,6 +262,12 @@
   void OnResponseStarted(const GURL& final_url,
                          const network::mojom::URLResponseHead& response_head);
 
+  // Called when SimpleURLLoader encounters a redirect.
+  void OnRedirect(const GURL& url_before_redirect,
+                  const net::RedirectInfo& redirect_info,
+                  const network::mojom::URLResponseHead& response_head,
+                  std::vector<std::string>* to_be_removed_headers);
+
   // Invokes callback with |code| and request to delete the request to
   // |sender_|.
   void CompleteRequestWithError(ApiErrorCode code);
diff --git a/google_apis/common/base_requests_unittest.cc b/google_apis/common/base_requests_unittest.cc
index 3892cff4..7fc435d40 100644
--- a/google_apis/common/base_requests_unittest.cc
+++ b/google_apis/common/base_requests_unittest.cc
@@ -18,7 +18,9 @@
 #include "google_apis/common/test_util.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
+#include "net/http/http_request_headers.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "services/network/network_service.h"
@@ -129,16 +131,36 @@
     task_environment_.RunUntilIdle();
   }
 
+  // Handles incoming HTTP requests on the primary test server. Records each
+  // request to verify header delivery and issues a 302 redirect for the
+  // `/redirect` path if a target URL is configured.
   std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
       const net::test_server::HttpRequest& request) {
-    std::unique_ptr<net::test_server::BasicHttpResponse> response(
-        new net::test_server::BasicHttpResponse);
+    received_requests_.push_back(request);
+    auto response = std::make_unique<net::test_server::BasicHttpResponse>();
+    if (redirect_location_.is_valid() && request.relative_url == "/redirect") {
+      response->set_code(net::HTTP_FOUND);
+      response->AddCustomHeader("Location", redirect_location_.spec());
+      return std::move(response);
+    }
     response->set_code(response_code_);
     response->set_content(response_body_);
     response->set_content_type("application/json");
     return std::move(response);
   }
 
+  // Handles incoming HTTP requests on the secondary cross-origin server.
+  // Records received requests to inspect headers delivered across origin
+  // boundaries.
+  std::unique_ptr<net::test_server::HttpResponse> HandleOtherOriginRequest(
+      const net::test_server::HttpRequest& request) {
+    other_origin_requests_.push_back(request);
+    auto response = std::make_unique<net::test_server::BasicHttpResponse>();
+    response->set_code(net::HTTP_OK);
+    response->set_content_type("application/json");
+    return std::move(response);
+  }
+
   base::test::TaskEnvironment task_environment_{
       base::test::TaskEnvironment::MainThreadType::IO};
   std::unique_ptr<network::mojom::NetworkService> network_service_;
@@ -148,9 +170,13 @@
       test_shared_loader_factory_;
   std::unique_ptr<RequestSender> sender_;
   net::EmbeddedTestServer test_server_;
+  net::EmbeddedTestServer other_origin_server_;
 
   net::HttpStatusCode response_code_;
   std::string response_body_;
+  GURL redirect_location_;
+  std::vector<net::test_server::HttpRequest> received_requests_;
+  std::vector<net::test_server::HttpRequest> other_origin_requests_;
 };
 
 TEST_F(BaseRequestsTest, ParseValidJson) {
@@ -198,6 +224,60 @@
   EXPECT_EQ(HTTP_SERVICE_UNAVAILABLE, error);
 }
 
+// Verifies that the Authorization header is removed when a request is
+// redirected to a cross-origin destination.
+TEST_F(BaseRequestsTest, AuthorizationHeaderRemovedOnCrossOriginRedirect) {
+  other_origin_server_.RegisterRequestHandler(base::BindRepeating(
+      &BaseRequestsTest::HandleOtherOriginRequest, base::Unretained(this)));
+  ASSERT_TRUE(other_origin_server_.Start());
+  ASSERT_NE(test_server_.base_url(), other_origin_server_.base_url());
+
+  redirect_location_ = other_origin_server_.GetURL("/target");
+
+  ApiErrorCode error = OTHER_ERROR;
+  base::RunLoop run_loop;
+  sender_->StartRequestWithAuthRetry(std::make_unique<FakeUrlFetchRequest>(
+      sender_.get(),
+      test_util::CreateQuitCallback(
+          &run_loop, test_util::CreateCopyResultCallback(&error)),
+      test_server_.GetURL("/redirect")));
+  run_loop.Run();
+
+  EXPECT_EQ(HTTP_SUCCESS, error);
+  ASSERT_EQ(1u, received_requests_.size());
+  EXPECT_NE(received_requests_[0].headers.end(),
+            received_requests_[0].headers.find(
+                net::HttpRequestHeaders::kAuthorization));
+  ASSERT_EQ(1u, other_origin_requests_.size());
+  EXPECT_EQ(other_origin_requests_[0].headers.end(),
+            other_origin_requests_[0].headers.find(
+                net::HttpRequestHeaders::kAuthorization));
+}
+
+// Verifies that the Authorization header is preserved when a request is
+// redirected to a same-origin destination.
+TEST_F(BaseRequestsTest, AuthorizationHeaderKeptOnSameOriginRedirect) {
+  redirect_location_ = test_server_.GetURL("/target");
+
+  ApiErrorCode error = OTHER_ERROR;
+  base::RunLoop run_loop;
+  sender_->StartRequestWithAuthRetry(std::make_unique<FakeUrlFetchRequest>(
+      sender_.get(),
+      test_util::CreateQuitCallback(
+          &run_loop, test_util::CreateCopyResultCallback(&error)),
+      test_server_.GetURL("/redirect")));
+  run_loop.Run();
+
+  EXPECT_EQ(HTTP_SUCCESS, error);
+  ASSERT_EQ(2u, received_requests_.size());
+  EXPECT_NE(received_requests_[0].headers.end(),
+            received_requests_[0].headers.find(
+                net::HttpRequestHeaders::kAuthorization));
+  EXPECT_NE(received_requests_[1].headers.end(),
+            received_requests_[1].headers.find(
+                net::HttpRequestHeaders::kAuthorization));
+}
+
 TEST(BaseRequestsHttpRequestMethodEnumTest, ConvertsToString) {
   EXPECT_EQ(HttpRequestMethodToString(HttpRequestMethod::kGet), "GET");
   EXPECT_EQ(HttpRequestMethodToString(HttpRequestMethod::kPost), "POST");
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/google_apis/common/base_requests_unittest.cc b/google_apis/common/base_requests_unittest.cc
index 3892cff4..7fc435d40 100644
--- a/google_apis/common/base_requests_unittest.cc
+++ b/google_apis/common/base_requests_unittest.cc
@@ -18,7 +18,9 @@
 #include "google_apis/common/test_util.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
+#include "net/http/http_request_headers.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "services/network/network_service.h"
@@ -129,16 +131,36 @@
     task_environment_.RunUntilIdle();
   }
 
+  // Handles incoming HTTP requests on the primary test server. Records each
+  // request to verify header delivery and issues a 302 redirect for the
+  // `/redirect` path if a target URL is configured.
   std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
       const net::test_server::HttpRequest& request) {
-    std::unique_ptr<net::test_server::BasicHttpResponse> response(
-        new net::test_server::BasicHttpResponse);
+    received_requests_.push_back(request);
+    auto response = std::make_unique<net::test_server::BasicHttpResponse>();
+    if (redirect_location_.is_valid() && request.relative_url == "/redirect") {
+      response->set_code(net::HTTP_FOUND);
+      response->AddCustomHeader("Location", redirect_location_.spec());
+      return std::move(response);
+    }
     response->set_code(response_code_);
     response->set_content(response_body_);
     response->set_content_type("application/json");
     return std::move(response);
   }
 
+  // Handles incoming HTTP requests on the secondary cross-origin server.
+  // Records received requests to inspect headers delivered across origin
+  // boundaries.
+  std::unique_ptr<net::test_server::HttpResponse> HandleOtherOriginRequest(
+      const net::test_server::HttpRequest& request) {
+    other_origin_requests_.push_back(request);
+    auto response = std::make_unique<net::test_server::BasicHttpResponse>();
+    response->set_code(net::HTTP_OK);
+    response->set_content_type("application/json");
+    return std::move(response);
+  }
+
   base::test::TaskEnvironment task_environment_{
       base::test::TaskEnvironment::MainThreadType::IO};
   std::unique_ptr<network::mojom::NetworkService> network_service_;
@@ -148,9 +170,13 @@
       test_shared_loader_factory_;
   std::unique_ptr<RequestSender> sender_;
   net::EmbeddedTestServer test_server_;
+  net::EmbeddedTestServer other_origin_server_;
 
   net::HttpStatusCode response_code_;
   std::string response_body_;
+  GURL redirect_location_;
+  std::vector<net::test_server::HttpRequest> received_requests_;
+  std::vector<net::test_server::HttpRequest> other_origin_requests_;
 };
 
 TEST_F(BaseRequestsTest, ParseValidJson) {
@@ -198,6 +224,60 @@
   EXPECT_EQ(HTTP_SERVICE_UNAVAILABLE, error);
 }
 
+// Verifies that the Authorization header is removed when a request is
+// redirected to a cross-origin destination.
+TEST_F(BaseRequestsTest, AuthorizationHeaderRemovedOnCrossOriginRedirect) {
+  other_origin_server_.RegisterRequestHandler(base::BindRepeating(
+      &BaseRequestsTest::HandleOtherOriginRequest, base::Unretained(this)));
+  ASSERT_TRUE(other_origin_server_.Start());
+  ASSERT_NE(test_server_.base_url(), other_origin_server_.base_url());
+
+  redirect_location_ = other_origin_server_.GetURL("/target");
+
+  ApiErrorCode error = OTHER_ERROR;
+  base::RunLoop run_loop;
+  sender_->StartRequestWithAuthRetry(std::make_unique<FakeUrlFetchRequest>(
+      sender_.get(),
+      test_util::CreateQuitCallback(
+          &run_loop, test_util::CreateCopyResultCallback(&error)),
+      test_server_.GetURL("/redirect")));
+  run_loop.Run();
+
+  EXPECT_EQ(HTTP_SUCCESS, error);
+  ASSERT_EQ(1u, received_requests_.size());
+  EXPECT_NE(received_requests_[0].headers.end(),
+            received_requests_[0].headers.find(
+                net::HttpRequestHeaders::kAuthorization));
+  ASSERT_EQ(1u, other_origin_requests_.size());
+  EXPECT_EQ(other_origin_requests_[0].headers.end(),
+            other_origin_requests_[0].headers.find(
+                net::HttpRequestHeaders::kAuthorization));
+}
+
+// Verifies that the Authorization header is preserved when a request is
+// redirected to a same-origin destination.
+TEST_F(BaseRequestsTest, AuthorizationHeaderKeptOnSameOriginRedirect) {
+  redirect_location_ = test_server_.GetURL("/target");
+
+  ApiErrorCode error = OTHER_ERROR;
+  base::RunLoop run_loop;
+  sender_->StartRequestWithAuthRetry(std::make_unique<FakeUrlFetchRequest>(
+      sender_.get(),
+      test_util::CreateQuitCallback(
+          &run_loop, test_util::CreateCopyResultCallback(&error)),
+      test_server_.GetURL("/redirect")));
+  run_loop.Run();
+
+  EXPECT_EQ(HTTP_SUCCESS, error);
+  ASSERT_EQ(2u, received_requests_.size());
+  EXPECT_NE(received_requests_[0].headers.end(),
+            received_requests_[0].headers.find(
+                net::HttpRequestHeaders::kAuthorization));
+  EXPECT_NE(received_requests_[1].headers.end(),
+            received_requests_[1].headers.find(
+                net::HttpRequestHeaders::kAuthorization));
+}
+
 TEST(BaseRequestsHttpRequestMethodEnumTest, ConvertsToString) {
   EXPECT_EQ(HttpRequestMethodToString(HttpRequestMethod::kGet), "GET");
   EXPECT_EQ(HttpRequestMethodToString(HttpRequestMethod::kPost), "POST");
Loading diff…

Original Bug Report

reported by [email protected]

Potential OAuth token leakage via cross-origin redirects in google_apis::UrlFetchRequestBase

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. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.

Overview: The UrlFetchRequestBase class, used by numerous browser-process Google API clients, fails to strip the sensitive Authorization header during cross-origin redirects. This behavior potentially discloses OAuth Bearer tokens to unauthorized third-party origins, violating Step 13 of the Fetch specification. Impacted services include Google Drive, Calendar, and YouTube Music, which may leak tokens through HTTP redirects or malicious server-supplied URLs.

Affected files:

  • google_apis/common/base_requests.cc
  • google_apis/drive/drive_base_requests.cc
  • google_apis/drive/drive_api_requests.cc

Estimated timestamp from git blame: Unknown (Google3 checkout)

Background

In Chromium, the google_apis::UrlFetchRequestBase class is the primary base class for browser-process HTTP requests to Google APIs. It manages authentication by attaching an Authorization: Bearer [token] header to requests dispatched via network::SimpleURLLoader.

Potential Root Cause

The vulnerability stems from the fact that UrlFetchRequestBase manually adds the Authorization header but does not register a redirect callback to ensure its removal during cross-origin transitions.

  1. Manual Header Attachment: In google_apis/common/base_requests.cc, UrlFetchRequestBase::StartAfterPrepare adds the header: request->headers.AddHeaderFromString(base::StringPrintf("Authorization: Bearer %s", access_token.data()));.
  2. Redirect Handling Omission: The class initializes SimpleURLLoader without calling SetOnRedirectCallback. When a redirect occurs, SimpleURLLoader follows it by default.
  3. Network Stack Behavior: In Chromium’s network stack, the net::RedirectUtil::UpdateHttpRequest utility (used by net::URLRequest) only strips headers explicitly provided in a removed_headers list. While Blink’s renderer-side ResourceLoader correctly populates this list with Authorization for cross-origin redirects, the browser-process implementation in UrlFetchRequestBase does not, leading to the header being preserved across origins.

Potential Exploitation Scenarios

An attacker could potentially receive a user’s OAuth token through two primary vectors:

  • Cross-Origin HTTP Redirects: If a targeted Google API endpoint (e.g., www.googleapis.com) has an open-redirect vulnerability or is manipulated via a network-level attack, an HTTP 301/302 response can redirect the authenticated request to https://attacker.test/, which would receive the Bearer token in the request headers.
  • Application-Level URL Injection: Some services, such as Google Drive, parse URLs from JSON responses (e.g., the nextLink field for pagination) or Location headers (for resumable upload session URLs). Analysis suggests these URLs are used blindly to initiate new authenticated requests. An attacker who can influence these fields (e.g., through a compromised network process or a specific API state) can direct a new request—complete with the Authorization header—to an arbitrary third-party origin.

Impact

This issue potentially affects every component using google_apis::RequestSender, including:

  • Google Drive: Disclosure of drive scope tokens.
  • Birch/Calendar: Disclosure of calendar.events.readonly tokens.
  • YouTube Music: Disclosure of focus-mode related tokens.
  • Glanceables (Tasks/Classroom): Disclosure of various productivity scopes.

Suggested Potential Steps to Trigger

Note: These steps are based on code analysis and have not been verified with a functional Proof of Concept.

  1. Sign in to a Chrome profile to ensure authenticated services are active.
  2. Trigger a background request from an affected service (e.g., a Drive sync or Calendar poll).
  3. Use a proxy or simulated network environment to return an HTTP 302 redirect from the Google API endpoint to an external domain (e.g., https://attacker.example/).
  4. Monitor the outgoing request to the external domain to verify if the Authorization: Bearer header is present.

Suggested Fix

  1. In UrlFetchRequestBase, implement a redirect callback using SimpleURLLoader::SetOnRedirectCallback that explicitly adds net::HttpRequestHeaders::kAuthorization to the removed_headers list if the redirect is cross-origin.
  2. Update Google API consumers (particularly in google_apis/drive/) to validate that any server-supplied URL (such as nextLink or upload session URLs) matches an expected Google origin before using it in a RequestSender flow.

Evaluated with Chrome root at commit: 1a8d40fc44df2088d5945c0bf53584038aa1614a


Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:

  • If you are familiar with the severity guidelines, you may adjust the severity.
  • If this is a false positive, and there’s no work to be done, please close as WAI.
  • If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.

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.

View on issue tracker