The target="_blank" vulnerability by example

Edit: Instagram has fixed this issue, presumably because of this article. Facebook and Twitter still have not. I used Instagram as the prime example, but the main takeaway is that the target="_blank" vulnerability is extremely common. The individual web developer should guard against it and the browsers should consider modifying this behavior.

If you use the target="_blank" attribute on a link, and do not accompany it with a rel="noopener" attribute, you are leaving your users open to a very simple phishing attack. We run a script that takes advantage of this issue in order to notify users when they come from a site that has not protected them from the vulnerability.

if (window.opener) {
  window.opener.location = "https://dev.to/phishing?referrer="+document.referrer;

I believe that the majority of websites do not deal with this issue properly, but I was surprised to find that Instagram.com was one of them. We just recently started an Instagram account for @ThePracticalDev and that is when we noticed the problem. If you click the dev.to link in our profile, and then go back to the original tab, you will see what I mean. Twitter also does not protect against this vulnerability on Safari, not Chrome or Firefox. They do not use rel="noopener" so it seems like the script they are using to accomplish this security is not working properly in Safari.

Edit: Because Instagram fixed the issue after this post went up I have changed the following example to Facebook Pages.

To clarify

  1. Visit The Practical Dev Facebook page.
  2. Click the dev.to link in the profile. This opens a new tab or window.
  3. Observe that the original tab has migrated to this page.

@ThePracticalDev Instagram Account

When a website uses target="_blank" on their links in order to open a new tab or window, that website gives the new page access to the existing window through the window.opener API, allowing it a few permissions. Some of these permissions are automatically negated by cross-domain restrictions, but window.location is fair game.

But wait, there's more

Not only is this an issue with phishing attacks, it is also a privacy concern because the newly opened website has ongoing access to the browsing location of the original tab. It can poll for this information and get the answer. Thankfully this behavior seems to fall under the cross-domain restrictions, so while I might gain access to certain ongoing information you might not expect me to know, there are sane restrictions that should likely apply to the entire spec.

Edit: When I first wrote this, I proposed a browser-spying scenario where a bad-actor could spy more thoroughly on a user's browsing history. I think that was inaccurate, so I modified the statement.

In order to restrict the behavior window.opener access, the original page needs to add a rel="noopener" attribute to any link that has target="_blank". However, Firefox does not support that tag, so you should actually use rel="noopener noreferrer" for full coverage. Some amount of prevention can be acheived through scripting, though, as observed with Twitter, this seems to fail on Safari.

var otherWindow = window.open();
otherWindow.opener = null;
otherWindow.location = url;

This script suggestion came from a good article on the subject.

This issue is not well-known, and is totally underestimated. This has been brought up in a Web Hypertext Application Technology Working Group mailing list. In my opinion, the risks of this browser behavior far outweigh the potential benefits. Either way, there are no excuses for Facebook and Instagram and Twitter to have overlooked this.

I'll have more to say about this kind of thing in the future. Follow me (@bendhalpern) or @ThePracticalDev on Twitter if you are interested.