Medium watch CVSS 4.3 chrome Spoofing 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
4.3
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactIncorrect security UI in LookalikeChecks
DescriptionIncorrect security UI in LookalikeChecks
ComponentLookalikeChecks
Bug ClassSpoofing
Action tierwatch — logic/policy bug — security-relevant, no memory-unsafety
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.
Tracker418214610
Fix commit19ca206a62d0 (chromium/src) +25/-0
CWECWE-451
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N
CISA KEVNot listed
CreditedNDevTK and Alesandro Ortiz
Reported2025-05-17 · bounty $10000 (per vendor advisory)
Fix landed2026-02-02 (public git)
Disclosed2026-03-10
Patch gap36 days — fix public in source before the advisory

Background

Ligatures (`liga`/`clig`)
OpenType font features that draw certain character sequences as one combined glyph (standard and contextual ligatures), so what is displayed can differ from the underlying characters.
`setFontFeatureSettings`
the Android TextView API that turns OpenType features on or off; the patch passes NO_LIGATURES ("\"liga\" 0, \"clig\" 0") to turn both ligature features off.
`PermissionDialogCoordinator`
the Android Java class that builds and shows modal site-permission dialogs, which include text identifying the requesting site.
Lookalike / incorrect security UI
a class of bug where security-relevant text, such as the origin in a permission prompt, can be made to look like a different, trusted value.

Root Cause Analysis

Android permission dialogs rendered their text with the font’s default ligatures turned on.

As a result, certain character sequences in dialog text, including the requesting origin (inferred), could be drawn as glyphs that read differently from the actual characters, which makes a lookalike origin more convincing. The commit says a matching mitigation was earlier applied to the omnibox (crrev.com/c/7199504), so permission dialogs had not received the same rendering hardening as the URL bar.

The fix adds UiUtils.disableLigaturesForSecurity(View), which walks a view tree recursively and calls setFontFeatureSettings(NO_LIGATURES) on every TextView. PermissionDialogCoordinator calls it on the dialog’s root view (rootView = dialogView) once, and again in the onGlobalLayout callback so that views added or re-laid-out later are covered. The diff does not show which specific ligature sequences produce a useful spoof.

Key insight
Security-sensitive text in the Android permission dialog was drawn with font ligatures turned on, so the glyphs shown could misrepresent the actual characters. The fix turns off liga and clig on every TextView in the dialog, matching the earlier omnibox mitigation.

Attack Path

  1. Register a crafted domain the attacker uses a hostname whose characters form ligatures in the system font that make it look like a different, trusted name (inferred: the diff does not name any sequence or font).
  2. Request a permission a page on that origin calls a permission-gated web API, so Chrome on Android shows a modal permission dialog that includes the site’s identity (inferred: the request entry point is not in the diff).
  3. Misleading rendering before the patch, the dialog’s TextViews rendered with default font features, so the ligatures changed how the origin looked.
  4. User grants the permission the user, who sees what looks like a trusted origin, grants the attacker’s site access to the requested capability (inferred).

Impact Assessment

The impact is a security-UI spoof in the browser’s own Android permission dialog: the attacker can make the displayed site identity misleading, so a user may grant a permission to the wrong site. The vendor rates it medium severity. It requires Chrome on Android (the changed code is under components/permissions/android and ui/android), a user who visits the attacker’s site, and a user decision to grant the permission. It does not involve memory corruption, and the advisory text supplied here does not report in-the-wild exploitation.

Changed Functions

FunctionChangeNotes
if
ui/android/java/src/org/chromium/ui/UiUtils.java
modified

Files Changed

  • components/permissions/android/java/src/org/chromium/components/permissions/PermissionDialogCoordinator.java
  • ui/android/java/src/org/chromium/ui/UiUtils.java

Audit Directions

  • Other surfaces that display origins
    check that every Android (and desktop) UI showing a host or origin, such as page info, download prompts, external-protocol dialogs, notification and PWA install prompts, gets the same disableLigaturesForSecurity treatment as the omnibox and permission dialogs.
  • Early returns that skip the mitigation
    verify that the hardening is applied on every display path, for example the branch that returns after recordOutOfScreenNegativeButton, and that views inflated or replaced later are re-covered.
  • Other rendering transforms
    review security-UI text for other font or shaping features (contextual alternates, bidi reordering, combining marks) that can make displayed text differ from the underlying characters.
From 19ca206a62d08ed290bcda7f5974b1cdb6a765c1 Mon Sep 17 00:00:00 2001
From: Mustafa Emre Acer <meacer@chromium.org>
Date: Mon, 02 Feb 2026 14:19:58 -0800
Subject: [PATCH] Disable ligatures in permission dialogs on Android

This change disables rendering of ligatures in permission dialogs
for security and readability. A similar change was previously made
for the omnibox in crrev.com/c/7199504.

Bug: 418214610
Change-Id: I4f0e61d87ea50304ef0909f939908393a81d9e78
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7536052
Reviewed-by: Sinan Sahin <sinansahin@google.com>
Commit-Queue: Mustafa Emre Acer <meacer@chromium.org>
Reviewed-by: Elias Klim <elklm@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1578393}
---

diff --git a/components/permissions/android/java/src/org/chromium/components/permissions/PermissionDialogCoordinator.java b/components/permissions/android/java/src/org/chromium/components/permissions/PermissionDialogCoordinator.java
index bd4876d..08329d0b 100644
--- a/components/permissions/android/java/src/org/chromium/components/permissions/PermissionDialogCoordinator.java
+++ b/components/permissions/android/java/src/org/chromium/components/permissions/PermissionDialogCoordinator.java
@@ -23,6 +23,7 @@
 import org.chromium.components.browser_ui.util.DimensionCompat;
 import org.chromium.components.content_settings.ContentSetting;
 import org.chromium.ui.LayoutInflaterUtils;
+import org.chromium.ui.UiUtils;
 import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.modaldialog.ModalDialogManager.ModalDialogManagerObserver;
 import org.chromium.ui.modaldialog.ModalDialogProperties;
@@ -76,12 +77,16 @@
                 recordOutOfScreenNegativeButton(lastButton);
                 return;
             }
+            final View rootView = dialogView;
+            UiUtils.disableLigaturesForSecurity(rootView);
+
             lastButton
                     .getViewTreeObserver()
                     .addOnGlobalLayoutListener(
                             new ViewTreeObserver.OnGlobalLayoutListener() {
                                 @Override
                                 public void onGlobalLayout() {
+                                    UiUtils.disableLigaturesForSecurity(rootView);
                                     if (!lastButton.isLaidOut()) {
                                         return;
                                     }
diff --git a/ui/android/java/src/org/chromium/ui/UiUtils.java b/ui/android/java/src/org/chromium/ui/UiUtils.java
index c27408c..17795258 100644
--- a/ui/android/java/src/org/chromium/ui/UiUtils.java
+++ b/ui/android/java/src/org/chromium/ui/UiUtils.java
@@ -77,10 +77,30 @@
     // this long after the prompt is displayed.
     public static long PROMPT_INPUT_PROTECTION_SHORT_DELAY_MS = 600;
 
+    // Font feature setting to disable ligature rendering.
+    private static final String NO_LIGATURES = "\"liga\" 0, \"clig\" 0";
+
     /** Guards this class from being instantiated. */
     private UiUtils() {}
 
     /**
+     * Recursively walks the view tree and disables ligatures on all TextViews
+     *
+     * @param view The root view{@link View}
+     */
+    public static void disableLigaturesForSecurity(View view) {
+        if (view instanceof TextView) {
+            ((TextView) view).setFontFeatureSettings(NO_LIGATURES);
+        }
+        if (view instanceof ViewGroup) {
+            ViewGroup group = (ViewGroup) view;
+            for (int i = 0; i < group.getChildCount(); i++) {
+                disableLigaturesForSecurity(group.getChildAt(i));
+            }
+        }
+    }
+
+    /**
      * Gets the set of locales supported by the current enabled Input Methods.
      *
      * @param context A {@link Context} instance.
Loading diff…

Original Bug Report

reported by al...@alesandroortiz.com

Security: Permission prompt spoofs with Google Sans font ligatures (similar to issue 391788835)

SUMMARY

Similar to issue 391788835, the Google Sans font ligatures can be used to spoof origin in various permission prompts.

VULNERABILITY DETAILS

While the fix for issue 391788835 (https://crrev.com/c/6227546) shows an interstitial for top-level navigations if the domain contains a blocked ligature, iframes are allowed to navigate to URLs with domains containing these ligatures.

An iframe at https://googlelogoligature.com can open a new window to about:blank which will still be in the origin with ligatures. The opener iframe can then request permissions using the origin with ligatures. All the permission UIs we tested don’t seem to sanitize these ligatures.

Affected permission prompts we’ve tested:

  • Camera
  • Microphone
  • Location
  • Notification
  • Read clipboard
  • Bluetooth
  • USB
  • Contacts

Probably all other permission prompts are affected.

VERSION

Verified repro on these versions:

Chrome version: 136.0.7103.87 Stable, 137.0.7151.23 Beta, 138.0.7178.0 Dev, 138.0.7180.0 Canary

Operating System: Android 14, Android 15

REPRODUCTION CASE

Setup:

  1. Make your Android device resolve googlelogoligature.com to your malicious server that hosts a downloadable file. In my case, my router lets me override DNS entries so it’s easy to test on physical device. For emulated devices, not sure if host’s DNS resolution would affect the emulated devices.
  2. Navigate once to https://googlelogoligature.com and accept the HTTPS warning (but NOT the fake site warning). Note that an attacker can get a valid cert for the ligature domains, so this is only needed for PoC.

Permissions scenarios

  1. Navigate to https://alesandroortiz.com/security/chromium/ligatures-perm.html
  2. Click anywhere.
  3. If indicated by instructions, click anywhere again. (This is for perm prompts that require user interaction.)

Repeat steps 1-3 for each variation using the in-page links.

Observed: Permission prompts shows spoofed origin (with font ligature).

Expected: Permission prompts show actual origin.

Credit Information

Reporter credit: NDevTK https://ndevtk.github.io/writeups/ and Alesandro Ortiz https://AlesandroOrtiz.com

View on issue tracker