CVE-2026-79222
Overview
Files Changed
chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.javachrome/android/javatests/src/org/chromium/chrome/browser/IntentHandlerNativeTest.javachrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
Patch
From 42fde8f7473ab60770518af2fef27b1782522ed7 Mon Sep 17 00:00:00 2001
From: Mohamed Adel <adelm@google.com>
Date: Mon, 06 Jul 2026 12:33:43 -0700
Subject: [PATCH] Fix origin check for Custom Tabs intent resolution
Update `CustomTabsConnection.isFirstPartyOriginForIntent` and related
tests to derive the origin from the actual resolved navigation URL using
`IntentHandler.getUrlFromIntent(intent)` rather than strictly from
`intent.getData()`.
Fixed: 496195129
Change-Id: I2b1037c5af643df9831052ba67979edbdbc10fc8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8033242
Reviewed-by: Theresa Wellington <twellington@chromium.org>
Reviewed-by: Sinan Sahin <sinansahin@google.com>
Auto-Submit: Moe Adel <adelm@google.com>
Commit-Queue: Theresa Wellington <twellington@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1657385}
---
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
index bf36da7d..a8e73f5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
@@ -1010,7 +1010,10 @@
SessionHolder<?> session = SessionHolder.getSessionHolderFromIntent(intent);
if (session == null) return false;
- Origin origin = Origin.create(intent.getData());
+ String url = IntentHandler.getUrlFromIntent(intent);
+ if (url == null) return false;
+
+ Origin origin = Origin.create(url);
if (origin == null) return false;
return mClientManager.isFirstPartyOriginForSession(session, origin);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/IntentHandlerNativeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/IntentHandlerNativeTest.java
index 48b0a4e..938a68dd 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/IntentHandlerNativeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/IntentHandlerNativeTest.java
@@ -186,7 +186,7 @@
() ->
ChromeOriginVerifier.addVerificationOverride(
"app1",
- Origin.create(headersIntent.getData()),
+ Origin.create(IntentHandler.getUrlFromIntent(headersIntent)),
CustomTabsService.RELATION_USE_AS_ORIGIN));
String extraHeaders = IntentHandler.getExtraHeadersFromIntent(headersIntent);
@@ -219,7 +219,7 @@
() ->
ChromeOriginVerifier.addVerificationOverride(
"app2",
- Origin.create(headersIntent.getData()),
+ Origin.create(IntentHandler.getUrlFromIntent(headersIntent)),
CustomTabsService.RELATION_USE_AS_ORIGIN));
String extraHeaders = IntentHandler.getExtraHeadersFromIntent(headersIntent);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
index 9db857f..0b18fc73d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -362,7 +362,7 @@
() ->
ChromeOriginVerifier.addVerificationOverride(
"app1",
- Origin.create(intent.getData()),
+ Origin.create(IntentHandler.getUrlFromIntent(intent)),
CustomTabsService.RELATION_USE_AS_ORIGIN));
final var session = warmUpAndLaunchUrlWithSession(intent);
Original Bug Report
Potential CCT first-party header gate bypass via intent.getData() / navigation-URL divergence
Project Fortify, an experimental security project, has identified the following potential security issue.
Overview: A discrepancy in how Chrome extracts a navigation URL versus how it verifies a first-party origin allows an attacker to send non-safelisted headers to arbitrary cross-origin sites in a Custom Tab. By placing their verified origin in intent.getData() and the target URL in EXTRA_TEXT, an attacker can bypass security checks and facilitate CSRF or session-based attacks.
Affected files:
chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.javachrome/android/java/src/org/chromium/chrome/browser/IntentHandler.javachrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.javachrome/android/java/src/org/chromium/chrome/browser/LaunchIntentDispatcher.java
Estimated timestamp from git blame: 2024-12-23
Overview
A potential security vulnerability exists in Chrome for Android where the Digital Asset Links (DAL) verification for Custom Tabs can be bypassed. This check is intended to restrict ’non-safelisted’ HTTP headers (such as Authorization or X-Csrf-Token) so they can only be sent to an app’s own verified domain. Due to a discrepancy in how the navigation URL is extracted versus how the DAL origin is determined, an attacker-controlled app can attach arbitrary sensitive headers to top-level cross-origin navigations.
Vulnerability Details
The CustomTabsConnection.isFirstPartyOriginForIntent() method determines if an app is a ‘first-party’ for a given intent’s origin using DAL verification. It derives the origin strictly from intent.getData():
Origin origin = Origin.create(intent.getData());
However, the actual navigation URL is resolved via IntentHandler.getUrlFromIntent(), which delegates to extractUrlFromIntent(). For certain intents, like ACTION_SEND with type text/plain, Chrome prioritizes fields like Intent.EXTRA_TEXT over intent.getData() for the navigation destination.
During early navigation processing (HiddenTabHolder.startEarlynavigation), Chrome uses the original intent to both extract the navigation URL and attach headers. Because the DAL check only looks at intent.getData(), an attacker can point intent.getData() to their own verified origin while pointing EXTRA_TEXT to the victim’s URL. The check passes, the CORS safelist filter is skipped, and the malicious headers are attached to the hidden tab’s request to the victim URL.
Subsequently, LaunchIntentDispatcher creates a sanitized launchIntent with its .setData() overwritten to the victim URL to start CustomTabActivity. In CustomTabActivityTabController.finishNativeInitialization, Chrome attempts to cancel any speculation if extra headers are present by calling IntentHandler.getExtraHeadersFromIntent(launchIntent). Because launchIntent.getData() is now the victim URL, the DAL check fails and the function returns null. This causes the cancellation check to fail, and the hidden tab successfully commits the cross-origin navigation with the injected headers.
Note: These are potential steps, as this analysis was performed by an AI agent (Fortify) without executing code to verify a working proof of concept.
Suggested Attacker Steps
- Setup: The attacker creates an Android app and completes DAL verification for an origin they control (e.g.,
https://attacker.example). - Session: The attacker app calls
CustomTabsClient.warmup()andCustomTabsClient.newSession(), verifying their relationship tohttps://attacker.exampleto ensure the DAL relationship is cached. - Intent Crafting: The app crafts an
Intent.ACTION_SENDintent with MIME typetext/plain. - Target and Origin: The app sets the intent’s data URI to their verified origin:
intent.setData(Uri.parse("https://attacker.example")). It sets the actual target victim URL in the extra text:intent.putExtra(Intent.EXTRA_TEXT, "https://victim.example/sensitive-action"). - Malicious Headers: The app bundles non-safelisted headers into the intent using the
Browser.EXTRA_HEADERSbundle (e.g.,Authorization: Bearer attacker_token). - Dispatch: The app launches the intent. Chrome’s early navigation mechanism processes the original intent, validates
intent.getData(), and launches a hidden tab tohttps://victim.examplewith the injected headers.
Suggested Fix
Modify CustomTabsConnection.isFirstPartyOriginForIntent(Intent intent) (and any similar checks) to derive the origin from the actual resolved navigation URL rather than strictly intent.getData(). Specifically, use IntentHandler.getUrlFromIntent(intent) to determine the origin being navigated to, ensuring the DAL check is performed against the true destination of the Custom Tab.
Evaluated with Chrome root at commit: bb48272cafb7e24c93f55ef40da398cd206ee651
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. Please feel free to reach out to me if you have concerns or feedback.