The browser feature attackers abuse

When you open a page in a tab and then switch to a different tab, the page in the background does not stop running. Its JavaScript keeps executing. Browsers throttle that execution (timers fire less often, animation frames slow down, CPU budget shrinks) but a page can still listen for events, run code on a schedule, and modify itself. Most importantly, it can detect that it is no longer the active tab.

The mechanism for that detection is the Page Visibility API on MDN. Two pieces of state expose the user's attention: document.hidden is a boolean that becomes true when the tab is no longer visible, and the visibilitychange event fires the moment that state flips. Both were designed for legitimate reasons (pausing video playback, throttling polling, pausing games when the user tabs away) and both are exactly what an attacker needs.

Once a page knows you are not looking at it, three more APIs let it transform itself into a different page without ever navigating. document.title can be assigned any string, so the tab label changes. The favicon (the little icon next to the title) is just a <link rel="icon"> tag, and replacing its href changes the icon. And document.body.innerHTML can be overwritten with an entirely new page. Together that is a complete cosmetic swap. The URL bar is the only thing that does not change, and on a phone or a narrow window the URL is often truncated or hidden.

The 5-step attack

Every tab nabbing campaign collapses to the same five beats. Different operators dress them up differently, but the skeleton is identical.

Step 1: You visit a legitimate-looking site

The attacker either compromises a real site (a hacked WordPress blog, an abandoned domain, a typosquatted docs mirror) or builds one that ranks for a low-traffic search query. The page itself is harmless on first visit. It may show you the article you searched for, a calculator widget, a free PDF, anything that gives you a reason to keep the tab open and walk away.

Step 2: You switch to another tab

The page is now in the background. Its visibilitychange listener fires. It checks document.hidden === true, starts a short timer (often 30 to 90 seconds, to be sure you really walked away rather than just glancing at a notification), and prepares the swap.

Step 3: The phishing tab silently rewrites itself

The script overwrites document.title to read "Gmail" or "Online Banking - Sign In" or the literal title string of whatever brand it is impersonating. It swaps the favicon href to a hosted copy of the Gmail icon. Then it replaces the page body with a pixel-perfect copy of the real login form, often pulled directly from the genuine site and minified inline.

Step 4: You come back to the tab later

An hour, a day, sometimes a week later. You scan your tab bar, see a Gmail icon and a "Gmail" label, and assume you left it open. Tab bars are visually compressed, especially in Chrome where 30 tabs collapse to icons only. The tab looks normal. The hostname in the address bar may not even be visible until you click the tab.

Step 5: You sign in

You type your email and password into the form. The form posts to the attacker. The page often follows up by redirecting to the real Gmail (or wherever) with a "session expired" message, so the failed login looks like a Google glitch rather than a phish. By the time you notice, the credentials are already being tested against every major site, and any account with the same password is compromised.

The original JS, with code

The entire trick is shorter than most users would believe. Here is a working tab nabbing payload in eight lines:

document.addEventListener('visibilitychange', () => {
  if (document.hidden) {
    setTimeout(() => {
      document.title = 'Gmail';
      document.querySelector("link[rel='icon']").href = '/gmail.png';
      document.body.innerHTML = FAKE_GMAIL_LOGIN_HTML;
    }, 60000);
  }
});

Read it line by line. The page registers a single event listener. When the tab loses focus, it waits 60 seconds (the timer is there so the swap does not happen if you only glanced at another tab), then rewrites the title, the favicon, and the body. There is no exploit, no CVE, no unpatched bug. Every API used here is a documented, intentional feature of every modern browser. The newer variant adds a check to make sure the user has not come back yet:

document.addEventListener('visibilitychange', () => {
  if (document.hidden && !window._swapped) {
    setTimeout(() => {
      if (document.hidden) {
        document.title = 'Online Banking';
        // ...swap favicon and body...
        window._swapped = true;
      }
    }, 90000);
  }
});

That double check guarantees the swap only happens if the tab has been ignored long enough to be plausibly forgotten, which both increases the attack success rate and reduces the chance a user catches the change live.

Why modern browsers do not fully block this

Browsers have spent a decade tightening what background tabs can do. Timer throttling slows down setTimeout and setInterval in inactive tabs. Animation frames pause. CPU budget gets cut. Audio can be paused. But visibilitychange still fires, document.title can still be assigned, the favicon <link> tag can still be rewritten, and the DOM can still be mutated. None of those changes break legitimate use cases (chat apps that show unread counts in the title, music players that change the icon while paused, web apps that swap their UI on tab focus) so the browser vendors will not remove them.

Same-tab navigation via window.location is partially restricted. A page can navigate itself to a same-origin URL with no friction. Cross-origin navigation initiated by JavaScript is allowed in most cases, but the browser may add a brief permission prompt or block it under certain conditions (cross-site iframes, sandboxed contexts). For tab nabbing, attackers usually skip the navigation entirely and rewrite the DOM in place, which avoids any cross-origin friction and keeps the original URL in the address bar where most users do not look.

The OWASP Tabnabbing entry still lists the attack as active, with the same defensive recommendations it had in 2014. The reason the recommendations have not changed is that the underlying browser behavior has not changed either.

Why tab hoarders are the target

A 2024 Avast survey of browser usage found that the average user keeps 15 to 30 tabs open during a typical session. Power users (developers, researchers, journalists, anyone doing multi-source work) routinely hit 50 or more. Some users never close tabs at all, treating the tab bar as a queue of unfinished business stretching back weeks.

Tab nabbing's success rate scales directly with that number. With 5 tabs open, a swapped tab is conspicuous; you notice the new icon. With 30, the tab bar is already a compressed strip of indistinguishable icons. The user is conditioned to scan for the icon they want, click it, and start using the page. The whole point of the attack is to take advantage of a UI element (the tab) that users have stopped paying close attention to.

The browsers know this. Tab groups, vertical tabs, tab search, tab pinning, the Discard Tab feature, all of it is a reaction to users carrying around hundreds of tabs. None of it changes the fact that a forgotten tab can rewrite itself while you are looking at something else.

Other variants in 2026

Two derivatives of the original attack are worth knowing about.

Reverse tabnabbing. When a site opens a new tab via target="_blank" without setting rel="noopener", the newly opened tab inherits a reference to the original tab via window.opener. The new tab can then call window.opener.location = 'https://attacker.example/fake-login' and silently navigate the original tab to a phishing page while the user is busy looking at the new tab. The Chromium team made rel="noopener" the default behavior for anchor-initiated target="_blank" links in 2021 (Chrome 88, January 2021), and Firefox and Safari followed. But the default does not apply to window.open() calls from JavaScript, and plenty of older sites still ship hand-written target="_blank" links without the attribute. Any user navigating those sites is still exposed.

The "page not responding" variant. A page detects it is in a background tab, then renders a convincing "This page has stopped responding. Click to reload" overlay. When the user comes back and clicks reload, the click is captured by an event listener that opens the real attack page in a new tab, or navigates the current tab to a credential harvester. The trick works because users expect background tabs to occasionally hang, and the "reload" instinct is hard to override.

How to defend

There is no single setting that disables tab nabbing. The defense is a small set of habits that compound.

  • Close unused tabs at the end of every day. The single most effective change. If a tab has been open for more than 24 hours and you cannot remember why, close it. You will reopen it from history if you actually need it. The fewer stale tabs you keep, the smaller the attack surface.
  • Check the URL in the address bar before entering credentials, every single time. No exceptions. A real Gmail login is on accounts.google.com. A real bank login is on the bank's domain. If the address bar shows anything else, do not type anything in. Our guide to spotting scam websites covers the URL patterns to watch for in detail.
  • Use a password manager that only autofills on the correct domain. 1Password, Bitwarden, Apple Passwords, and Google Passwords all bind credentials to the exact origin where they were saved. When the password manager refuses to autofill, that is the single strongest signal a tab is fake. You will not get visual cues from the page itself; the manager is the canary.
  • Pin the tabs you actually use. Pinned tabs are visually distinct (smaller, fixed position, no close button) and harder to confuse with a forgotten tab.
  • If a tab claims to have "expired" your session, close it and navigate to the site fresh from a bookmark. Do not click a "sign in again" button on a tab that has been open for hours.

How SafeBrowz fits in

Tab nabbing leaves a trail at the browser layer. The moment a tab tries to navigate to an attacker-controlled domain (or post a login form to one), SafeBrowz inspects the destination against our brand-impersonation engine and the live blocklist. If the tab is rewriting itself in place and only the form submission goes external, we catch the submit. If the tab navigates outright, we catch the navigation. Either way the credentials never reach the attacker. That said, the password manager remains the strongest single defense, because it refuses to type into the fake page in the first place. SafeBrowz is the second layer for the cases where autofill is off or the user types manually. The SafeBrowz extension is free forever for phishing and brand impersonation blocking on Chrome, Firefox, and Edge.

FAQ

Is tab nabbing the same as a popup or a redirect?

No. A popup opens a new window. A redirect navigates the current page. Tab nabbing leaves the original tab in place and rewrites its contents in JavaScript without any navigation event the user can see. The URL bar often does not change.

Does HTTPS protect me from tab nabbing?

HTTPS protects the connection between you and the server. It does nothing about what the server's own JavaScript does inside the page. A tab nabbing attack is served over HTTPS just like any other modern site.

Will closing the tab fix it?

Yes, but only if you do it before you enter credentials. Once you have typed your password into the fake form and pressed submit, the data is gone. Close all tabs from the same browsing session and change the password immediately on a fresh tab navigated from a bookmark.

Does private or incognito mode help?

Slightly. Private windows clear state when closed, so a tab nabbing page cannot persist across sessions. But within a single private window the attack works exactly the same as in a normal window.

Is reverse tabnabbing still a problem after Chrome's 2021 fix?

It is reduced but not eliminated. Anchor-initiated target="_blank" links now default to rel="noopener" in Chrome, Firefox, and Safari, so the most common entry point is closed. JavaScript-initiated window.open() calls do not get the same default, and many third-party sites still ship hand-written links without the attribute. Treat unknown sites as if the fix were not there.

How is tab nabbing different from ClickFix or pastejacking?

ClickFix tricks you into manually running attacker-supplied commands. Pastejacking swaps the contents of your clipboard between copy and paste. Tab nabbing rewrites a tab you already had open. All three exploit a moment when the user is not paying full attention, but the mechanics are completely different. Read also our guide to spotting Microsoft phishing emails for related credential-harvesting tactics.