Request
a demo

The Magic Link Vulnerability

A year ago, our security team discovered a vulnerability in magic links that changed our industry's approach to wallet authentication.

Last year, in February 2023, Dfns' security team found a serious flaw in the login process of several apps that use magic links. This issue could have let someone take complete control of user accounts and wallets.

In this post, we'll review what happened, explain the attack in more detail, and evaluate how effective our preventative measures have been.

Nothing magic with magic links

Magic links are a type of passwordless login that uses a single-use link to authenticate users. They are seen as a secure option compared to traditional passwords and have been adopted by many large companies, often through providers like Okta. Companies such as Rakuten, GoDaddy, HubSpot, Zoom, Salesforce, and Slack use them. This magic link vulnerability poses major risks to the digital economy, including the digital asset industry, affecting companies and wallets like Magic, Web3Auth, Sequence, Stytch, and others.

Although magic links are often used for email verification, our research showed they were not suitable for creating accounts, registering users, creating wallets, signing transactions, or other sensitive activities related to digital assets. Our findings highlighted security weaknesses in using magic links for authentication, calling for a thorough reevaluation of secure login practices across the industry, particularly for wallets. Despite their similar appearance, crypto wallets and email inboxes are not the same and require different approaches to risk and security.

The design of magic links is straightforward. It basically delegates the authentication security to the user's email provider. In other words, the authentication security is as strong as the user’s email account security, assuming it's implemented correctly. However, achieving this can be challenging, as we'll discuss in this article.

To use magic link authentication, a user inputs their email address on the website they wish to access. The website generates an authentication token and creates a unique link, which it sends to the user’s email inbox. The user then clicks on this link in their email, which redirects them back to the website. The website checks the token and logs the user in.

Here’s how it works, step by step:

  1. The user visits the website https://this-site-implements-magic.link and enters their email address <user@mail.com>.
  2. The website creates an authentication token. This is often a jwt token, but the exact format can vary.
  3. The website generates a unique URL: https://this-site-implements-magic.link/confirm?token=<auth token>. It includes this URL in an email and sends it to the user’s email address: <user@mail.com>.
  4. The user checks their email, finds the email from https://this-site-implements-magic.link, opens it, and clicks on the link
  5. The website extracts the authentication token from the URL, checks it, and logs the user in.

To make the first step work, the website needs an unauthenticated API to send the magic link to the user. The popularity of magic link solutions grew because they allow users to onboard quickly. This authentication flow merges signup and login. Even if a user doesn't exist, the API generates a magic link and sends an email. This means the process can start with any valid email address, whether or not the user is already in the system.

Another point is that to improve user experience, websites want users to log in from any page and return to that page after authentication. So, let's update our initial example to accommodate this use case:

  1. The user visits the website https://this-site-implements-magic.link/awesome-content and decides to log in using the magic link feature available on all pages.
  2. The user types their email address (user@mail.com) into the magic link widget.
  3. The website (this-site-implements-magic.link) creates an authentication token.
  4. The website then generates a unique URL: https://this-site-implements-magic.link/confirm?token=<auth token>&redirect_url=/awesome-content. It sends this URL to the user's email address.
  5. The user checks their email, finds the message from this-site-implements-magic.link, and clicks on the provided link.
  6. When the user clicks the link, the website verifies the authentication token in the URL and logs in the user. It then redirects the user to the /awesome-content page.

Companies now offer products that serve as third-party authentication providers, allowing websites to implement magic link authentication without any coding. Here’s how it works:

  1. A website like https://this-site-implements-magic.link includes an authentication widget from a provider like magic-link-identity-provider.com.
  2. The user enters their email address (e.g., user@mail.com) into the widget.
  3. The identity provider, magic-link-identity-provider.com, generates an authentication token.
  4. The provider creates a unique URL: https://magic-link-identity-provider.com/confirm?token=<auth_token>&redirect_url=https://this-site-implements-magic.link.
  5. The user checks their email, clicks on the link from magic-link-identity-provider.com.
  6. The identity provider’s website extracts and verifies the token from the URL, then redirects the user to https://this-site-implements-magic.link, passing the token as a parameter.
  7. The website https://this-site-implements-magic.link checks the token’s validity to authenticate the user.

The redirect_url tells us where to send the user after they log in successfully. This is typically set by the client when a user asks for a magic link to log in.

Let’s play an attack scenario

Putting all of this together, we can build the following attack scenario:

  1. The attacker uses an open API on a website to request a special "magic link" that is sent to the victim's email but redirects to a website controlled by the attacker.
  2. The victim gets a legitimate email from the real website—this isn't a fake email; it's actually sent by the website they trust.
  3. The victim clicks on the link in the email.
  4. This link logs the victim in automatically, so they think everything is normal.
  5. But after logging in, the victim is redirected to the attacker's website, which secretly steals the valid login token.
  6. The attacker quickly sends the victim back to the original website, making the process seem fast and invisible to the victim.
  7. Now, the attacker has a valid token to access the victim's account on the website.

It's important to note that this attack relies on the victim clicking the link in the email, which they are very likely to do as the link is sent by the trusted source and can be timed at the moment when the user logs in. This makes it easier for the attacker to deceive the victim.

The different mitigation strategies

Here are some ways to prevent this type of attack:

  1. Don't allow the setting of the redirect URL from the unauthenticated API that creates the magic link. This can be tough to do in systems where the service that manages identity is separate from the main website.
  2. Make sure the redirect URL is from a list of approved URLs or domains. This means keeping the list correct and current, which isn't always easy.
  3. Check that the device clicking the link is the same one that asked for it. This might make things a bit more difficult for users.

Blitzpatching millions of wallets

It's been a year since our last risk assessment, and we're pleased to report significant progress in using magic links for authentication. Companies like Magic and Web3Auth have moved away from magic links, opting instead for solutions like email one-time passwords.

Magic's SDK 3.0 logs indicate that they removed the magiclink pull request method from their documentation. Their README now states that they no longer support magic links, which currently leads to a 404 error page. These changes were made in March 2023, shortly after we disclosed the vulnerability.

Some companies, like Stytch, continue to use magic links but now require that the redirect URL be on a pre-approved list. Additionally, the widely used Next Auth JS library by default allows redirect URLs only from the same domain: https://next-auth.js.org/configuration/callbacks#redirect-callback.

Our initial intention when discovering the vulnerability was to pursue a Common Vulnerability and Exposures (CVE) identifier but MITRE asked us to specify affected products. Given the sheer number of services utilizing magic links, direct CVE filing for each wasn’t feasible.

In light of this discovery, we strongly advised all organizations and application providers to take immediate action to protect their users and data. The measures we recommended directly mitigated the exploitation of magic link vulnerabilities and significantly enhance overall security:

  • Disable magic links: This functionality presents a significant security risk and should be avoided entirely.
  • Implement one-time passwords (OTPs): OTPs provide a more secure alternative to magic links for user authentication.
  • Enforce two-factor authentication (2FA): Wherever possible, implement 2FA as an additional layer of security beyond passwords.

3 days after the Coindesk article by Sam Kessler, we were pleased to announce that we had achieved substantial progress in preventing potential thefts of digital assets and sensitive data in collaboration with several companies.

The need for widespread public disclosure

Dfns also actively engaged with the broader security community. We informed various security institutions like SANS, NIST and MITRE to increase overall awareness and contribute to industry-wide response against this threat. While this attack could have caused significant damage if carried out by malicious actors, the Dfns team successfully identified the vulnerability and supported several affected parties before harm occurred. It is important to note that Dfns and its staff provided assistance without any financial incentive.

References