CVE-2026-95321
Overview
Background
- Secure Payment Confirmation (SPC)
- a web payments mechanism where the browser displays a trusted, browser-controlled dialog showing the payment instrument the user is about to authenticate with WebAuthn.
- Payment instrument display name
- the user-facing label (and detail row) identifying a card or account, often including distinguishing suffixes such as the last four card digits.
- `android:ellipsize`
- an Android
TextViewattribute that controls how text exceeding the view’s bounds is truncated;endappends a trailing ellipsis to signal that content was cut off. - `android:maxLines`
- an Android
TextViewattribute limiting the number of rendered lines, which silently clips overflow when noellipsizebehavior is set.
Root Cause Analysis
On Chrome Android, the SPC dialog rendered the payment instrument’s primary and secondary text rows from payments_instrument.xml using android:maxLines="1" without any android:ellipsize attribute. When a display name exceeded the available width, Android clipped the overflow at the view boundary with no visual indication, so trailing characters — including the distinguishing card-digit suffix — were silently dropped from the user’s view. This violated the invariant that the trusted payment UI must faithfully represent the instrument being authorized, allowing two instruments whose names differ only in a truncated suffix to appear identical.
The fix adds android:ellipsize="end" to both the primary and secondary TextView elements, matching Desktop behavior so that any truncation is now visibly marked with a trailing ellipsis. The accompanying SecurePaymentConfirmationViewBinderTest.java assertions confirm both views report TextUtils.TruncateAt.END, locking in the corrected rendering.
android:maxLines="1" with no android:ellipsize value, causing overflowing instrument names to be truncated invisibly; adding android:ellipsize="end" restores a visible cue so users can tell that the displayed name is incomplete.Attack Path
- Craft a long instrument name
An attacker or ambiguous data source arranges for a payment instrument whose display name or detail row is long enough to overflow the single-line
TextViewon a typical Android device width. - Trigger the SPC dialog
A payment flow invokes Secure Payment Confirmation, and Chrome renders the instrument rows from
payments_instrument.xmlwithmaxLines="1"and no ellipsize. - Silent truncation hides the suffix
Android clips the overflowing text with no trailing ellipsis, omitting distinguishing characters such as the card-digit suffix, so the visible name matches another, different instrument.
(inferred) - User authorizes under misapprehension
Believing they are confirming the intended instrument, the user completes the WebAuthn authentication for a payment they did not intend to distinguish.
(inferred)
Impact Assessment
LogicError); no exploited-in-the-wild status is stated, and any escalation to actual fraudulent authorization beyond the display flaw is (inferred).Files Changed
components/payments/content/android/minimal_java_res/layout/payments_instrument.xmlcomponents/payments/content/android/spc/javatests/src/org/chromium/components/payments/secure_payment_confirmation/SecurePaymentConfirmationViewBinderTest.java
Audit Directions
- maxLines without ellipsizeSearch Android layout XML for
android:maxLines(especially="1") onTextViewelements in trusted or security-sensitive UI that lack a matchingandroid:ellipsize, since these silently clip overflow. - Trusted UI parity across platformsCompare Desktop and Android renderings of security-critical dialogs (Payments, permissions, WebAuthn) for divergent truncation or formatting behavior that could hide distinguishing details.
- Distinguishing-suffix omissionReview UI that displays identifiers whose trailing portion carries the disambiguating information (card digits, account tails, hostnames) to ensure overflow never drops the discriminating suffix without a visible cue.
Patch
From 56388ada0d24833af302df56c319db7b6f6f5a6d Mon Sep 17 00:00:00 2001 From: Stephen McGruer <[email protected]> Date: Thu, 20 Aug 2026 08:16:27 -0700 Subject: [PATCH] [SPC] Ellipsize payment instrument display name on overflow Previously, on Chrome Android, the payment instrument display name and details rows in Secure Payment Confirmation (SPC) had maxLines="1" without an ellipsize attribute. As a result, long display names were silently truncated without any visual indication (e.g. trailing ellipsis), omitting distinguishing suffixes like card digits. This CL adds android:ellipsize="end" to the primary and secondary text views in payments_instrument.xml to match Desktop behavior and ensure overflow is visibly indicated with an ellipsis. Bug: 545879261 Test: components_junit_tests -f "*SecurePaymentConfirmation*" Change-Id: I21488659e5c410508b243d45e67d6849e4642354 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8272448 Commit-Queue: Stephen McGruer <[email protected]> Reviewed-by: Darwin Yang <[email protected]> Cr-Commit-Position: refs/heads/main@{#1683170} --- diff --git a/components/payments/content/android/minimal_java_res/layout/payments_instrument.xml b/components/payments/content/android/minimal_java_res/layout/payments_instrument.xml index fb211521..337aa72 100644 --- a/components/payments/content/android/minimal_java_res/layout/payments_instrument.xml +++ b/components/payments/content/android/minimal_java_res/layout/payments_instrument.xml @@ -32,6 +32,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:maxLines="1" + android:ellipsize="end" android:includeFontPadding="false" android:textAppearance="@style/TextAppearance.TextMedium.Primary" /> <TextView @@ -39,6 +40,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:maxLines="1" + android:ellipsize="end" android:includeFontPadding="false" android:textAppearance="@style/TextAppearance.TextMedium.Primary" android:visibility="gone"/> diff --git a/components/payments/content/android/spc/javatests/src/org/chromium/components/payments/secure_payment_confirmation/SecurePaymentConfirmationViewBinderTest.java b/components/payments/content/android/spc/javatests/src/org/chromium/components/payments/secure_payment_confirmation/SecurePaymentConfirmationViewBinderTest.java index 3a90a17f..10ab93f 100644 --- a/components/payments/content/android/spc/javatests/src/org/chromium/components/payments/secure_payment_confirmation/SecurePaymentConfirmationViewBinderTest.java +++ b/components/payments/content/android/spc/javatests/src/org/chromium/components/payments/secure_payment_confirmation/SecurePaymentConfirmationViewBinderTest.java @@ -15,6 +15,7 @@ import android.graphics.Color; import android.graphics.drawable.BitmapDrawable; import android.text.SpannableString; +import android.text.TextUtils; import android.view.View; import android.widget.ImageView; import android.widget.TextView; @@ -259,9 +260,15 @@ assertSame(icon, ((ImageView) itemView.findViewById(R.id.icon)).getDrawable()); assertEquals(iconLabel, itemView.findViewById(R.id.icon).getContentDescription()); assertEquals(primaryText, ((TextView) itemView.findViewById(R.id.primary_text)).getText()); + assertEquals( + TextUtils.TruncateAt.END, + ((TextView) itemView.findViewById(R.id.primary_text)).getEllipsize()); assertEquals(View.VISIBLE, itemView.findViewById(R.id.secondary_text).getVisibility()); assertEquals( secondaryText, ((TextView) itemView.findViewById(R.id.secondary_text)).getText()); + assertEquals( + TextUtils.TruncateAt.END, + ((TextView) itemView.findViewById(R.id.secondary_text)).getEllipsize()); } @Test