Bug: URL bar spoofing with bidirectional Unicode characters (also link hover text)
Status: RESOLVED
Priority: P3
Resolution: FIXED
Created: 2021-02-05 08:04:52+00:00
Resolved: 2024-05-30 17:26:57+00:00

The URL bar content can be spoofed by mixing bidirectional Unicode characters in specific ways, allowing an attacker to forge the displayed protocol and host.

I'm reporting two variants. (1) is Firefox-specific and seems to be facilitated by URL trimming. (2) affects both Firefox and Google Chrome and seems to point to a general issue with how the parts of bidirectional URLs are reordered.

**(1)**
In a text, the first occurring *strong* (i.e. directional) character determines the base direction. In the URL bar, this is usually the `h` of `http`. However, Firefox strips `http://` from plain HTTP URLs (if `browser.urlbar.trimURLs == true`, as is the default). In that case, the first character of the hostname determines the text direction. So, if a hostname from an RTL script is chosen (which passes the IDN display algorithm without being altered, e.g. an Arabic or Hebrew word), the entire URL string is displayed with RTL as the base direction. This arranges parts of the URL in unexpected ways.

**Proof of concept**
- [`http://xn--tib.ml/index%F0%90%A9%96https://www.mozilla.org/articles`](http://xn--tib.ml/index%F0%90%A9%96https://www.mozilla.org/articles) appears in the URL bar as `https://www.mozilla.org/articles𐩖ml/index.ٴ`, spoofing both the HTTPS protocol and full host. (I've chosen an Arabic letter as the second-level domain name and an RTL slash-lookalike (`U+10A56`) as a convincing path separator, although the latter isn't a requirement for the attack.)
- Similarly, a hostname with European numbers (because they aren't *strongly* directional) and an RTL top-level domain could be used, e.g.: [`http://123.456.קום/https://www.mozilla.org/articles`](http://123.456.קום/https://www.mozilla.org/articles) which displays as `https://www.mozilla.org/articles/קום.123.456`

**(2)**
Both Firefox and Google Chrome seem to implement the same display algorithm for URLs with bidirectional text, which gives unexpected results if both the hostname and path contain RTL sequences. In particular, if the hostname ends with an RTL part, and the path starts with an RTL character, both are interpreted as a continuous RTL context and get visually re-ordered. This way part of the path ends up in the hostname and vice versa. This also means that an attacker can (visually) inject characters into the hostname which are on the IDN blocklist but don't get blocked here because they are actually part of the path segment, not the domain name.

**Proof of concept**
- [`https://www.mozilla.org.xn--tib.xn--9dbq2a/#%F0%90%A9%96/app/main`](https://www.mozilla.org.xn--tib.xn--9dbq2a/#%F0%90%A9%96/app/main) displays as `https://www.mozilla.org.𐩖#...`
- Also, an RTL-only hostname can trivially be shadowed by another RTL hostname: [`https://ק.קום/م.كوم/foo`](https://ק.קום/م.كوم/foo) requests `ק.קום` although visually `م.كوم` follows after the protocol part.
- Since numbers aren't strongly directional, one can also trivially spoof IP hosts. E.g., [`https://127.xn--9dbq2a/0.0.1/`](https://127.xn--9dbq2a/0.0.1/) and [`https://127.ק.קום/0.0.1/index.php`](https://127.ק.קום/0.0.1/index.php) both visually start with `https://127.0.0.1/` but request a different hostname.

All examples were tested on Linux + Nightly with default settings.