CVE-2026-5895
Overview
Background
- Location bar steady view
- the iOS omnibox component (
location_bar_steady_view.mm) that renders the current page’s URL as aUILabelwhen the omnibox is not being edited. - RTL paragraph alignment
- a text-layout behavior where a label containing right-to-left characters flips the writing direction of the whole paragraph, visually reordering its runs.
- IDN with RTL scripts
- internationalized domain names using right-to-left scripts (e.g. Arabic/Hebrew), which embed RTL characters into the URL string shown in the location bar.
- `NSWritingDirectionLeftToRight`
- the Cocoa paragraph-style attribute that pins a label’s base writing direction to left-to-right regardless of its character content.
Root Cause Analysis
The steady view set its URL label by assigning a plain NSString to self.locationLabel.text, inheriting the label’s default writing direction. When the URL contained RTL characters (such as an IDN using an RTL script), the label switched to RTL paragraph alignment and visually reversed the order of URL components, so the top-level domain rendered on the left instead of the right. Because users judge a site’s domain authority by the right-most label, this reordering misrepresents which domain is actually loaded.
The fix replaces the plain-text assignment with an NSAttributedString carrying an NSMutableParagraphStyle whose baseWritingDirection is forced to NSWritingDirectionLeftToRight, guaranteeing LTR visual order for the URL. The new setLocationLabelText:clipTail: overload also folds the truncation mode into the same paragraph style, replacing the separate lineBreakMode assignment previously done in the view controller. This is a UI-correctness fix (forcing a fixed writing direction), not a check tightening on untrusted parsing.
NSWritingDirectionLeftToRight via an attributed-string paragraph style so the TLD always stays on the right.Attack Path
- Craft an RTL-bearing URL An attacker registers or links to a URL whose displayed form contains RTL characters, for example an IDN using an RTL script, so the location-bar string mixes LTR and RTL runs.
- Victim navigates on iOS Chrome
The page loads and
updateLocationText:clipTail:pushes the URL string into the steady view’s label. - Label flips to RTL order With the pre-patch plain-text assignment, the label adopts RTL paragraph alignment and reorders the URL components, rendering the TLD on the left.
- Domain misread The user sees a reordered URL whose right-most component is no longer the real registrable domain, creating a spoofing opportunity about the site’s identity.
Impact Assessment
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifios/chrome/browser/location_bar/ui_bundled/location_bar_steady_view.mm |
modified |
Files Changed
ios/chrome/browser/location_bar/ui_bundled/location_bar_steady_view.hios/chrome/browser/location_bar/ui_bundled/location_bar_steady_view.mmios/chrome/browser/location_bar/ui_bundled/location_bar_view_controller.mm
Audit Directions
- Unconstrained writing direction in security UIAudit other surfaces that display URLs or origins (tab titles, permission prompts, page-info) for plain-text assignment that lets content-derived RTL flip visual order.
- Bidirectional-text rendering of untrusted stringsReview any label/text view showing attacker-controllable strings for missing
baseWritingDirection/ Unicode bidi isolation, per the URL display guidelines referenced in the patch. - IDN handling across platformsCompare the iOS location bar against desktop/Android omnibox code to confirm each enforces LTR URL display for RTL-script IDNs.
Patch
From f545d50577ba5a72a89e1495293d5d4bc52b64a4 Mon Sep 17 00:00:00 2001
From: Ameur Hosni <ameurhosni@google.com>
Date: Wed, 18 Feb 2026 02:26:31 -0800
Subject: [PATCH] [IOS] Fix RTL URL component reordering in the location bar
This change fixes a visual issue where URLs containing RTL characters
(e.g., IDN with RTL scripts) would cause the Location Bar label to
switch to RTL paragraph alignment.
This resulted in the visual reversal of URL components, displaying the
Top-Level Domain on the left instead of the right, which could be
misleading regarding the site's actual domain authority.
Before: https://screenshot.googleplex.com/5KFCzgU68rw3D4D
After: https://screenshot.googleplex.com/zJ8fo6KTKNGDgiZ
Fixed: 470395720,374285495
Change-Id: I33884fc685cb7f9a26c93d67167b4f5529cbb668
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7581320
Reviewed-by: Gauthier Ambard <gambard@chromium.org>
Commit-Queue: Ameur Hosni <ameurhosni@google.com>
Cr-Commit-Position: refs/heads/main@{#1586307}
---
diff --git a/ios/chrome/browser/location_bar/ui_bundled/location_bar_steady_view.h b/ios/chrome/browser/location_bar/ui_bundled/location_bar_steady_view.h
index 0cccea9..26b1e25 100644
--- a/ios/chrome/browser/location_bar/ui_bundled/location_bar_steady_view.h
+++ b/ios/chrome/browser/location_bar/ui_bundled/location_bar_steady_view.h
@@ -43,6 +43,10 @@
// Sets the location label's text.
- (void)setLocationLabelText:(NSString*)string;
+// Sets the location label's text. `clipTail` indicates whether the label should
+// truncate the tail or the head.
+- (void)setLocationLabelText:(NSString*)string clipTail:(BOOL)clipTail;
+
// Sets the location label's text and styles it as if it were placeholder text.
- (void)setLocationLabelPlaceholderText:(NSString*)string;
diff --git a/ios/chrome/browser/location_bar/ui_bundled/location_bar_steady_view.mm b/ios/chrome/browser/location_bar/ui_bundled/location_bar_steady_view.mm
index f9e5a44d..a32e0a0 100644
--- a/ios/chrome/browser/location_bar/ui_bundled/location_bar_steady_view.mm
+++ b/ios/chrome/browser/location_bar/ui_bundled/location_bar_steady_view.mm
@@ -429,11 +429,23 @@
}
- (void)setLocationLabelText:(NSString*)string {
- if ([self.locationLabel.text isEqualToString:string]) {
- return;
- }
+ [self setLocationLabelText:string clipTail:NO];
+}
+
+- (void)setLocationLabelText:(NSString*)string clipTail:(BOOL)clipTail {
+ // Use attributed text to force LTR direction for URLs, preventing RTL
+ // characters from messing up the visual order (e.g. IDN with RTL scripts).
+ NSMutableParagraphStyle* style = [[NSMutableParagraphStyle alloc] init];
+ // https://chromium.googlesource.com/chromium/src/+/HEAD/docs/security/url_display_guidelines/url_display_guidelines.md#rtl
+ [style setBaseWritingDirection:NSWritingDirectionLeftToRight];
+ [style setLineBreakMode:clipTail ? NSLineBreakByTruncatingTail
+ : NSLineBreakByTruncatingHead];
+
+ NSDictionary* attributes = @{NSParagraphStyleAttributeName : style};
+
+ self.locationLabel.attributedText =
+ [[NSAttributedString alloc] initWithString:string attributes:attributes];
self.locationLabel.textColor = self.colorScheme.fontColor;
- self.locationLabel.text = string;
[self updateAccessibility];
}
diff --git a/ios/chrome/browser/location_bar/ui_bundled/location_bar_view_controller.mm b/ios/chrome/browser/location_bar/ui_bundled/location_bar_view_controller.mm
index 2be6102f..056f6c9e 100644
--- a/ios/chrome/browser/location_bar/ui_bundled/location_bar_view_controller.mm
+++ b/ios/chrome/browser/location_bar/ui_bundled/location_bar_view_controller.mm
@@ -423,9 +423,7 @@
#pragma mark - LocationBarSteadyViewConsumer
- (void)updateLocationText:(NSString*)string clipTail:(BOOL)clipTail {
- [self.locationBarSteadyView setLocationLabelText:string];
- self.locationBarSteadyView.locationLabel.lineBreakMode =
- clipTail ? NSLineBreakByTruncatingTail : NSLineBreakByTruncatingHead;
+ [self.locationBarSteadyView setLocationLabelText:string clipTail:clipTail];
}
- (void)updateLocationIcon:(UIImage*)icon
Original Bug Report
Chrome iOS Address Bar Spoof Using 2 RTL (Arabic Characters) Subdomains
Security Bug
VERSION
Chrome Version: 130.0.6723.37 (Official Build) stable (64-bit) Operating System: iOS 18 on iPhone 16
REPRODUCTION CASE
- Using Chrome iOS open
https://xn--llb.login.wwww.accounts.google.com.xn--llb.pwr.wtf/
Expected Result
Address bar showing ە.login.wwww.accounts.google.com.ە.pwr.wtf/
Actual Result
Address Bar shows pwr.wtf.ە.ogin.wwww.accounts.google.com...
Details
The issue arises when using 2 RTL characters in different level subdomains and in between add a domain that we want to spoof. First we add a RTL character then any domain we want to spoof and in the end we add another RTL character that will confuse the address bar and mixes up the RTL LTR showing of the URL.
CREDIT INFORMATION
Reporter credit: Renwa Hiwa @RenwaX23