Security insights

Magic Links and Account Takeover: Where Teams Get It Wrong

A magic link is a password sent by email. We just stopped calling it that. An essay on how passwordless authentication won the SaaS world, what nobody wants to admit about it, and why the most secure-looking login flow in your product might be the worst one you ship.

BU
BugSwagger Team

I want to start with a question that doesn't have a comfortable answer. Why did magic links win?

Walk through any new SaaS sign-up flow built in the last three years and you'll see one. Slack uses them. Notion uses them. Vercel, Linear, Substack, dozens more — the developer-tools, the productivity apps, the startups whose founders read the same blog posts. The pitch is so clean it almost designs itself: no passwords. Nothing to forget, nothing to leak, nothing to crack. You type your email, you get a link, you click it, you're in. The whole thing feels modern. It also feels safe.

The reason this question doesn't have a comfortable answer is that the safety part is mostly a feeling. Magic links are not, in any technical sense, more secure than passwords. They are a different way of carrying a credential. The credential lives in your email instead of in your head. That trade is real, and it goes in both directions, and most of the security industry has been notably quiet about the direction it goes against.

Let me show you what I mean.

A magic link is, structurally, a token. The token is generated by your server, sent to a user's email address, and accepted by your server when the user submits it back. If the token is valid, the user is logged in. Compare that to a password: a string generated by the user, hashed and stored by your server, and submitted by the user to log in. The two are not very different shapes. They are both shared secrets, and in both cases the security of the secret determines the security of the account. The only meaningful structural difference is where the secret lives between uses. Passwords live in the user's head. Magic links live in their inbox.

This sounds like a small detail. It is the entire story. Because once the credential lives in the user's email, the security of your authentication system is, in a very direct way, no stronger than the security of that user's email account. If their email is compromised, your application is compromised. If their email has weak password reuse, your application inherits the weakness. If their email provider has a breach, your application is in the blast radius — even though you have done nothing wrong on your side.

Passwords had a similar inheritance problem in the opposite direction. If a user reused their password across services, a breach at one service compromised them everywhere. The industry's response was a long, slow campaign in favor of password managers, MFA, breached-credential checking, and unique random passwords. We spent a decade telling users to do better. Most of them eventually did.

What we did not do, in the same campaign, was acknowledge that magic links bypass the entire MFA layer by routing through email. If a user has MFA enabled on Gmail, their magic link is reasonably safe. If their email is on a small Exchange server with no MFA — or, worse, on a personal address that hasn't been audited in years — the magic link arrives in a folder protected only by a password the user picked in 2014. Your shiny new passwordless system has the security posture of that folder.

This is the part nobody wants to say out loud, because it makes the whole magic-link movement sound less impressive than it is in the pitch decks. Magic links did not eliminate the password attack surface. They moved it to a different system that you don't control.

The token is the credential, and the token has problems

The shift in mental model — "the token is the credential" — is one most engineers building magic-link flows have not fully internalized. You can tell because the magic-link implementations we audit consistently fail on credential-quality issues that everyone agrees would be unacceptable for passwords.

The most common failure: tokens with insufficient entropy. We have found magic-link implementations that generate six-digit codes. Six digits is one million possibilities. If your endpoint is rate-limited generously — say, 100 attempts per minute — an attacker can brute-force a specific user's token in under a week. If your endpoint is not rate-limited at all (and many aren't, because "no one will guess a token"), the brute force completes in minutes. Compare that to even a weak password: nobody would ship a system that accepted six-digit passwords for production accounts.

The second common failure: tokens that don't expire. The right window is somewhere between five and fifteen minutes. We routinely find tokens that work for hours. We have, on more than one occasion, found tokens that work indefinitely. This means: an email forwarded six months ago, sitting in a colleague's archive, is still a valid login. Nobody would ship a password that worked forever after a single email forward. Magic links get this pass because they "feel ephemeral." They aren't, unless you make them.

The third: tokens that work more than once. The standard implementation is single-use — once the link is clicked, it dies. Lazier implementations let the token work for as many clicks as occur within the expiration window. The bug here is subtle: any system that previews the link before the user does (a Slack link unfurler, a corporate URL scanner, a mail client's safe-link rewriter) gets to consume the token first. The user clicks the link, finds it dead, requests a new one, gets confused. Meanwhile, the entity that previewed the link — sometimes an automated system, sometimes a malicious actor — has the working credential.

This third class is interesting because it is where magic links and passwords actually diverge. A password is something only the user knows. A magic link is something the user's entire email pipeline knows — every server that handled the message, every preview bot that fetched the URL, every backup system that archived the inbox. The attack surface is wider by an order of magnitude. The security comes from constraining the use of the token, not from secrecy of the token itself.

The bugs we actually find

Let me give you three real ones, lightly anonymized.

The first was a developer-tools SaaS with a magic-link flow that returned the login link in the HTTP response body of the request to send it. The intent, I think, was for the frontend to display the link to the user during development. In production, the same endpoint behaved the same way. Any unauthenticated user could request a magic link for any email address and read the login link from the response. The fix was a one-line change: return only a confirmation, not the link. The bug had been in production for over a year. (A similar CVE — CVE-2026-39912 in v2board's loginWithMailLink endpoint — was disclosed publicly in 2026; the pattern recurs.)

The second was a B2B platform whose magic links included a redirect parameter, so the user would land on the right page after logging in. The redirect was not validated. An attacker could send a victim a legitimate magic link with the redirect pointed at https://attacker.com. The victim clicked the link, logged in, and was redirected to the attacker's site — with the original login token in the URL fragment, which the attacker's site then exfiltrated. The attacker then completed the login flow themselves and was inside the victim's account. The Arrive app's 2020 HackerOne disclosure (#855618) documents almost exactly this pattern; the attack vector is mature and well-understood, and it still keeps appearing.

The third was a SaaS app that did almost everything right. Cryptographically strong tokens, short expiration, single-use, redirect validation. The bug was operational: their email-sending infrastructure used a transactional email provider whose support reps could read message bodies for debugging. A social-engineered support rep — and these things have been social-engineered before — could read a target user's pending magic-link email and use the token. The provider had access controls on this, sure. But the access controls were the kind that get audited annually by a third party who looks at a SOC 2 report. The point is that the magic-link flow had pushed the security boundary out of the application and into the email provider's support workflow. The team that built the flow had never considered that boundary.

What I keep coming back to is that none of these bugs were in the cryptography. The cryptography of magic links is mostly fine. The bugs are in the assumptions the team made about who, exactly, has access to the user's email and the URL contents inside it. Those assumptions are almost always wrong.

The CSRF that wasn't supposed to be possible

There is a particularly elegant version of this whole class of bug that bears its own attention. Consider: a magic link is a URL. URLs get followed by all kinds of things. Slack expands URLs to generate link previews — Slack's bots fetch the URL. Mail clients scan URLs for malware — those scanners fetch the URL. Corporate proxies prefetch URLs to warm caches — those proxies fetch the URL.

If your magic link is "click this URL to log in," every one of those side-effecting consumers reaches your login endpoint before the user does. In the lucky case, the token gets consumed by Slack's preview bot. The user clicks the link, finds it expired, gets confused, requests another. Annoying but not catastrophic.

In the unlucky case, the consumer is now logged in. Specifically: if your login endpoint sets a session cookie on the response, and the consumer is something with a cookie jar (some scanners are), you've just bound a session to whatever bot or scanner is on the other end. The user, when they later click the link, gets the expired-token error. The session, meanwhile, belongs to the scanner.

This sounds far-fetched until you remember that the same primitive describes a CSRF attack. An attacker who can get a victim's email client to preview the link — by sending an email containing a quoted forwarded version of the magic link, for instance — can sometimes induce the preview to "log in" with the token before the user does.

The defense is straightforward and almost universally absent in poorly-implemented systems: the magic link should not log the user in directly. It should land on a page that requires user interaction — a "Sign in" button to click — before the session is created. The preview bots stop at the page; only the human gets past it. We covered the broader CSRF picture in a separate article, but the magic-link variant deserves its own callout, because the bug is so easy to ship without realizing.

The companies that get this right (and what they actually do)

It would be unfair to spend this much time on the problems without acknowledging that some teams have figured out the pattern. Slack's magic-link flow, for instance, is reasonable: cryptographically strong tokens, short expiration, click-through confirmation page, session binding to the requesting browser. Notion does similar things. Vercel's auth flow is one of the more carefully thought-through I've audited.

If you read what these companies actually shipped, a few patterns emerge. The token is long (well over 128 bits of effective entropy). The link expires quickly (ten to fifteen minutes is typical). The click-through page is mandatory. The token is single-use. And — this is the bit most teams miss — the token is bound to the originating session or device fingerprint. If you request a magic link from your laptop and try to use it from your phone, the system notices and starts a different flow.

That last bit is the one that quietly closes most of the email-pipeline-as-attack-surface problems. If the token is bound to your laptop, then a Slack preview bot consuming it doesn't matter; the bot isn't your laptop. A forwarded email doesn't matter; the new recipient's device isn't your laptop. An attacker who has read the email but is not on your machine doesn't matter; their device isn't your laptop.

The session-binding step is also the most commonly missed in implementations we audit. It's not in the textbook description of magic-link flows. It's not in the popular tutorials. It's the thing teams skip when they're racing to ship, and it's the thing that, in retrospect, separates the safe implementations from the dangerous ones.

What I think this all means

Here is what I think the right way to read this is. Magic links are not bad. They are not, in any deep sense, worse than passwords. They are also not, in any deep sense, better. They are a different way of solving the same problem — getting a long credential from the user to your server — and they come with a different set of trade-offs that you, the team shipping them, have to actually think about.

The trap is that magic links feel like a security upgrade. They aren't. They are a security re-architecture. You have moved your authentication strength from your password storage (your problem) to your user's email security (their problem, sort of, often actually nobody's problem). For some products and some user populations, that re-architecture is a net win. For others, it isn't. You should know which you are before you ship the design.

If you are a founder evaluating whether your app's magic-link flow is well-built, the questions I would ask aren't "do we have magic links" but: what's the entropy of the token, what's the expiration window, is it single-use, is it bound to the requesting session, and does the link require an explicit click-through before logging in. If your team can answer all five with confident specifics — including numbers — your implementation is probably fine. If any of the answers is "I'd have to check," the answer is probably also "fix it."

If you are an engineer who has shipped a magic-link flow recently and any of this article made you uncomfortable, the discomfort is the article doing its job. The good news is that the fixes are short. The interesting news is that you can't fix what you haven't audited.

The best version of this for sensitive accounts isn't magic links at all, by the way. It is passkeys (WebAuthn) — credentials that genuinely live on the device, not in the email inbox, with cryptographic verification on every login. The industry has been slow to move because passkey UX is still rough, but the security model is qualitatively better. If you're building authentication for a high-value B2B product in 2026 and you're still designing around magic links, that's a choice worth justifying. Most of the time, the justification is "they're easier to ship." Which is true. It is also exactly why the bugs persist.

The verdict, then. Magic links solved a real problem — the user-experience disaster of password management. They did so by moving the security boundary to a system most teams have never specifically audited. Sometimes that move is fine. Often it isn't. The question worth asking, when you next look at your login flow, is whether you have actually checked which one you're in.

Found this helpful?

Want a hand-tested assessment for your own stack?

Tell us what you're protecting — we'll respond within one business day with a scoped proposal written by a pentester.