Protecting Your Apps From Link-based Vulnerabilities: Reverse Tabnabbing, Broken-Link Hijacking, and Open Redirects
Tags: security
Published: 2020-08-11 22:04:27

*This article was originally written by [Julien Cretel][1] on the [Honeybadger Developer Blog][2].*  
Links! They're the very fabric of the Web. Browsing simply wouldn't be possible without them. Creating and following links feels so natural that you probably don't stop very often to wonder about the risks associated with them. In this post, I want to cover three vulnerabilities involving links: broken-link hijacking, open redirects, and reverse tabnabbing.

## Broken-link hijacking

You probably share useful resources in your blog posts, on your social networks, etc. By linking to some third-party website and inviting your readers, though, you're implicitly establishing some kind of contract with them. You're essentially saying:

> Hey! We believe that the resource accessible at the end of this link could be of interest to you, and we vouch for the trustworthiness of the site that hosts it. :)
>

However, can you guarantee that the resource will remain accessible and unaltered forever? Not if the resource is outside of your control. After all, the Web is in a constant state of flux, and [link rot][link-rot] is real because, for example, websites restructure their content, companies rebrand or are acquired, and domains expire.

[_Broken-link hijacking_][edoverflow] is an attack whereby a facetious (if not malicious) actor notices a dead link in your content and manages to take control of what lies at the end of that link.

### Impact

What could a broken-link hijacker do, in practice? Here is a funny example.

In April 2011, Donald Trump posted a tweet in which he announced he would attend the [2012 National Achievers Congress][nac]; he also shared the URL of the congress's website (`www.nac2012.com`) in his tweet. At some later stage, the congress organizers let the `nac2012.com` domain lapse, which then caused the link in Trump's tweet to break. After noticing that the domain was available for purchase, Belgian ethical hacker [Inti de Ceukelaire][inti] bought the domain and playfully redirected it to a Youtube video lampooning Trump. From then on, any unsuspecting person viewing [Trump's tweet][trump-tweet] would be led to believe that Trump himself willingly tweeted a video in which he is the object of satire!

![Trump's tweet hijacked by hacker](https://www.honeybadger.io/images/blog/posts/link-vulnerabilities/trump_tweet.png)
_Trump's tweet hijacked by hacker_

Tweets can't be edited, only deleted; nonetheless, the tweet has endured ever since. The most likely explanation for its longevity is that nobody on Trump's team ever noticed Inti's prank.

You may think this hijacked tweet is an isolated example, but it's not. A few years later, a hacker then known as @MisterCh0c [defaced multiple tweets][celebs] by celebrities, such as Shakira and Katy Perry. These examples may cause you to chuckle, but broken-link hijacking is widespread and can have more dramatic consequences on organizations.

A couple of months ago, I noticed that the Facebook social link on a multimillion-dollar company's website was pointing to a non-existent Facebook profile. As I knew the company was running a bug-bounty program, I claimed the Facebook account for myself, personalized "my" status (as a proof of concept), and reported the vulnerability to their security team, who promptly fixed it.

A happy ending, but imagine how a malicious broken-link hijacker could have taken advantage of the situation. The link to the hijacker-controlled Facebook profile on the company's website would have indeed lent the hijacker enough legitimacy to impersonate the company on the social network. The hijacker could have

- posted offensive content meant to harm the company's reputation,
- elicited sensitive information from distressed customers, or
- distributed malware,

all the while pretending to be a legitimate representative of the company. Incidentally, the company recognized the potential impact of such a vulnerability and decided to reward me with a 3-digit bounty. Not bad for a ten-minute job. 😛

### Remediation

There is no easy defense against broken-link hijacking. The best thing you can do is to regularly scrape your own website, tweets, etc., inspect broken links, and audit all outbound links. Consider outsourcing this task by setting up a bug-bounty program and reward reports of broken-link hijacking (among other vulnerabilities, of course).

## Open redirects

You've probably come across endpoints in the form of

```
https://example.org/redirect?url=
```

that accept a URL and redirect visitors to that location, with little to no preliminary validation. Such endpoints are known as [_open redirects_][cwe-601]; variations in terminology abound, but let's not linger on that here.

Because tampering with the `url` query parameter is straightforward
and because sharing URLs is trivial, open redirects can easily be
weaponized against you and your users. Unfortunately, open redirects are [widespread on the Web][openbugbounty]: many organizations simply dismiss them as inconsequential. However, let's examine why you may not want to have open redirects on your main domain.

### Impact

The sad truth is that the presence of open redirects on your domain
opens the door to all kinds of abuse.

Before long, search engines may start referencing pages that are
seemingly hosted on your website, but whose content you're not responsible for and with which you most likely don't want to be associated! For instance, think of a few lewd or offensive terms, stick them at the end of the following [Google dork][google-dork], and run the search.

```
site:edu inurl:&
```

You'll quickly get a sense of how many respectable universities unwittingly appear to host questionable content on their websites. Of course, they're not. Rather, most of the offending results stem from the presence of open redirects on the universities' domains that some nasty sites are taking advantage of to generate inbound traffic.

Open redirects are also valuable for phishing purposes because
they allow malicious links to look safe by "hiding" behind a reputable domain name. Most security-conscious people probably wouldn't click on a link like

```
https://evilzone.org
```

because the hostname betrays its maliciousness, but what about this one?

```
https://example.org/redirect?url=https%3a%2f%2fevilzone.org
```

Or this one (in which I've to obfuscated the query parameter by percent-encoding it)?

```
https://example.org/redirect?url=%68%74%74%70%73%3a%2f%2f%65%76%69%6c%7a%6f%6e%65%2e%6f%72%67
```

Whether even tech-savvy people would smell a rat here is doubtful.

If you're still unconvinced that open redirects are bad, be aware that they often play a crucial role in exploit chains. When combined with other vulnerabilities, they may, for example, enable attackers to bypass protection (e.g., against [server-side request forgery][owasp-ssrf]) or steal auth tokens. In fact, seasoned ethical hackers know better than to immediately report open redirects to organizations that happen to run a bug-bounty program. Such hackers would rather [keep an open redirect close to their chest][keep-open-redirect] and bide their time until they figure out how to chain it with other vulnerabilities to achieve greater impact. By doing so, they'll be able to collect a larger bounty.

### Remediation

In many cases, you could and should only accept a finite number of trusted URLs and reject all others. In other cases, some functionalities demand that all URLs be accepted, such as on sites that allow user-generated content and funnel all outbound traffic through one of their endpoints (for analytics purposes, presumably).
Such sites should consider either

1. hosting the endpoint on a distinct, dedicated domain, or
2. presenting an interstitial page to their users when they leave the site.

[Slack][slack], for instance, follows the first approach. Every time you click on a link rendered as `https://example.org` within Slack,
you're sent to

```
https://slack-redir.net/link?url=https%3A%2F%2Fexample.org
```

which then redirects you to `https://example.org`. Note that this open redirect is hosted on a dedicated domain (`slack-redir.net`)
to avoid compromising Slack's main domain (`slack.com`).

[HackerOne][h1] follows the second approach and shows users an interstitial page when they're about to navigate to an untrusted third-party site. Such a page is essentially meant as a warning:

> You may not have realized it, but you're about to leave our site.
> We cannot vouch for your safety beyond this point.
> Be careful; here be dragons!

![HackerOne's interstitial page](https://www.honeybadger.io/images/blog/posts/link-vulnerabilities/hackerone_interstitial.png)
_HackerOne's interstitial page_

For more guidance about remediating open redirects, check out
[OWASP's cheat sheet][owasp-open-redirect] on the topic.

## Reverse tabnabbing

Some links are designed to open the linked document in a new browser tab/window (I'll use the terms "tab" and "window" interchangeably, here). This can be achieved in both HTML and JavaScript. In HTML, specifying `_blank` as the value of the anchor element's `target` attribute will do the trick:

```html
<a href="https://eff.org" target="_blank">Click me!</a>
```

As for the JavaScript DOM API, simply invoking `window.open`
will cause the linked document to open in a new tab:

```javascript
window.open("https://eff.org");
```

Because the browser runs the new window in the same process as the first window, it allows for a modicum of interaction between the two, regardless of the respective [_origins_][mozilla-origin] of the two windows. In particular, the first window can change the location of the second one. Here is an example:

```html
<script>
  function delayedRickRoll() {
    var newWindow = window.open("https://eff.org");
    setTimeout(() => {
      const url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ";
      newWindow.location.replace(url);
    });
  }
</script>
Support the <a href="javascript:delayedRickRoll()">EFF</a>!
```

The document contains a seemingly innocent link. When you follow that link, the landing page of the Electronic Frontier Foundation's website opens in a new tab. However, two seconds later, the JavaScript code running in the context of the first tab sets the location of the second tab to a Youtube video of Rick Astley's infamous 1987 song, "Never Gonna Give You Up". You've just been [rick-rolled][urban-dictionary] with only a two-second delay.

What's perhaps more surprising is that the opposite is possible!
By default, the second window holds, through its `opener` property,
a reference to the window that opened it (i.e., the first window);
unless some precautions are taken by the document in the first tab,
the second tab can simply change the location of the first tab!
A kind of [_spooky action at a distance_][quantum], if you will.

Here is an example. If you click on an innocent link, such as this one:

```html
<a href="https://tabnabbing-attack.jub0bs.com" target="_blank">
  Click me!
</a>
```

and the linked document consists of the following code:

```html
<h1>Not Found</h1>
<p>The requested URL was not found on this server.</p>
<hr />
<address>
  Apache/2.2.15 (Red Hat) Server at tabnabbing-attack.jub0bs.com on Port 443
</address>
<script>
  const url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ";
  window.opener.location.replace(url);
</script>
```

then, the linked document (masquerading as a fake Apache error page)
will open in a new tab but immediately set the location of the first tab to the Rick Astley video! Try it for yourself [here][vulnerable].

<img src="https://www.honeybadger.io/images/blog/posts/link-vulnerabilities/rickroll_via_tabnabbing.gif?1595966278" alt="Rick-rolling via reverse tabnabbing" style="width: 100%;">

This subterfuge—a window altering its opener's location—is known as [_reverse tabnabbing_][owasp-tabnabbing], and it is considered a security issue. Why? Well, being rick-rolled can be amusing or, perhaps, irritating, but is rather innocuous. However, I'm sure you can imagine how malicious actors could be tempted to exploit this reverse tabnabbing for a more insidious kind of evil, namely phishing.

### Impact

Consider, for example, a banking site that would be vulnerable to reverse tabnabbing:

1. You open your browser and navigate to the landing page of your banking site, perhaps to check your balance.
2. Before you log in, some link on the landing page catches your eye. You click on it, which causes a third-party site to open in a second tab.
3. Unbeknownst to you and your bank, the third-party site is malicious. While you're focused on the new tab, the document therein accesses its opener and redirects the first tab to some phishing site that's meant to look just like your banking site.
4. You eventually close the second tab and return to the first tab.
You still believe the site you're seeing is your banking site; you didn't notice that the address of the first tab changed because you were too busy looking at the third-party site in the second tab at the time.
5. You confidently enter your banking credentials, thereby handing them over to whoever controls the phishing site. You've just been pwned!

This example may suffice to convince you that reverse tabnabbing is no laughing matter.

### Remediation

Fortunately, the remedy to reverse tabnabbing is simple; for each outbound link meant to open in a new tab, prevent the linked document from accessing its opener.

In HTML, specify the `noopener` [_link type_][link-types] in the `rel` attribute
of each outbound link's anchor element:

```html
<a href="https://tabnabbing-attack.jub0bs.com"
   target"_blank"
   rel="noopener">
  Click me!
</a>
```

Doing so will cause the linked document to hold no reference to its opener (its `window.opener` property will simply be `null`), which will thwart any reverse-tabnabbing attack. Try it for yourself [here][protected]; inspect the console of the second tab after following the link, and you should see something like

```
TypeError: window.opener is null
```

The `noopener` link type enjoys [widespread support in modern browsers][caniuse] but isn't supported in any version of Internet Explorer. However, Internet Explorer does support link type `noreferrer`, which prevents any referrer information from being communicated to the linked document. Because [`noreferrer` implies `noopener`][implies] in browsers that support the latter,
`noreferrer` is preferable to `noopener`.

You can achieve the same protection against reverse tabnabbing in JavaScript; simply specify the required link type in the [third argument][window-features] to `window.open`:

```javascript
window.open(
  "https://tabnabbing.jub0bs.com",
  "window name", // irrelevant, here
  "noreferrer"
);
```

## Conclusion

Although you create and follow links every day, there's more to them than meets the eye, especially in terms of security. Understanding these three vulnerabilities—broken-link hijacking, open redirects, and reverse tabnabbing—is key to reducing your attack surface and effectively keeping your users and yourself safe.

[caniuse]: https://caniuse.com/#search=noopener
[celebs]: https://hackernoon.com/how-i-hijacked-top-celebrities-tweets-including-katy-perry-shakira-fca3a0e751c6
[cwe-601]: https://cwe.mitre.org/data/definitions/601.html
[edoverflow]: https://edoverflow.com/2017/broken-link-hijacking/
[google-dork]: https://www.exploit-db.com/google-hacking-database
[h1]: https://www.hackerone.com/
[implies]: https://html.spec.whatwg.org/multipage/links.html#link-type-noreferrer
[inti]: https://twitter.com/securinti
[keep-open-redirect]: https://www.youtube.com/watch?v=o-tL9ULF0KI&t=6m55s
[link-rot]: https://en.wikipedia.org/wiki/Link_rot
[link-types]: https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types
[mozilla-origin]: https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#Definition_of_an_origin
[nac]: https://web.archive.org/web/20120216232728/http://www.nac2012.com/
[openbugbounty]: https://www.openbugbounty.org
[owasp-open-redirect]: https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html
[owasp-ssrf]: https://owasp.org/www-community/attacks/Server_Side_Request_Forgery
[owasp-tabnabbing]: https://owasp.org/www-community/attacks/Reverse_Tabnabbing
[protected]: https://protected-against-tabnabbing.jub0bs.com
[quantum]: https://en.wikipedia.org/wiki/Quantum_entanglement
[slack]: https://slack.com/
[trump-tweet]: https://twitter.com/realdonaldtrump/status/190093504939163648
[urban-dictionary]: https://www.urbandictionary.com/define.php?term=rick%20rolled&defid=2415540
[vulnerable]: https://vulnerable-to-tabnabbing.jub0bs.com
[window-features]: https://developer.mozilla.org/en-US/docs/Web/API/Window/open#Window_features
[1]: https://www.honeybadger.io/blog/link-vulnerabilities/#authorDetails
[2]: https://www.honeybadger.io/blog/link-vulnerabilities/