[GH-ISSUE #7196] changeEmail Vulnerability: Account Takeover via Typo in New Email Address #28080

Closed
opened 2026-04-17 19:28:21 -05:00 by GiteaMirror · 15 comments
Owner

Originally created by @mohhh-ok on GitHub (Jan 8, 2026).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/7196

Originally assigned to: @bytaesu on GitHub.

The current auth.api.changeEmail implementation creates a critical security vulnerability that allows unintended account takeover when users make a typo in their new email address.

Current Flow

  1. User requests email change to a new address
  2. Confirmation link sent to old email
  3. User clicks old email confirmation link → Database immediately updated to new email
  4. Verification email sent to new email address

Vulnerability Scenario

  1. User A wants to change email to alice@example.com but accidentally types aliceee@example.com (typo)
  2. User A receives confirmation link in their old email
  3. User A clicks the confirmation link (assuming the new email is correct)
  4. Account email is immediately changed to aliceee@example.com in the database
  5. The owner of aliceee@example.com (unknown third party) receives the verification email
  6. Third party clicks verification link OR uses "Forgot Password" flow
  7. Account takeover complete - User A is now locked out of their own account

Additional Security Issue: No Session Validation

The verification links do not validate the user's session or require authentication:

  • Verification links can be opened in incognito/private browser windows
  • No cookie or session check is performed
  • Anyone with access to the link can complete the verification without proving they own the account

This means:

  • If someone gains access to the email (forwarded email, compromised email account, shared computer), they can complete the verification without knowing the account password
  • The link itself is the only authentication factor, with no additional validation

Why This is Critical

  • Users typically don't re-verify the new email address when clicking the old email confirmation
  • Typos in email addresses are extremely common
  • Once the database is updated (step 4), the original owner loses control
  • The third party who receives the verification email can complete the takeover
  • No session validation means links can be used by anyone, anywhere

Expected Behavior

The email change should follow a two-step verification process:

  1. User requests email change
  2. Confirmation link sent to old email
  3. User clicks old email link → Change marked as "pending" (no database update yet)
  4. Verification link sent to new email
  5. User clicks new email link → Only now update the database
  6. Invalidate all tokens to prevent reuse
  7. Verify that the user is authenticated when clicking verification links

Instead of verification links, use OTP (One-Time Password) codes:

  1. User must be logged in to change email
  2. Send OTP to new email → user enters code in authenticated session
  3. Update database only after OTPs verified
Originally created by @mohhh-ok on GitHub (Jan 8, 2026). Original GitHub issue: https://github.com/better-auth/better-auth/issues/7196 Originally assigned to: @bytaesu on GitHub. The current `auth.api.changeEmail` implementation creates a critical security vulnerability that allows unintended account takeover when users make a typo in their new email address. ## Current Flow 1. User requests email change to a new address 2. Confirmation link sent to **old email** 3. User clicks old email confirmation link → **Database immediately updated** to new email 4. Verification email sent to new email address ## Vulnerability Scenario 1. User A wants to change email to `alice@example.com` but accidentally types `aliceee@example.com` (typo) 2. User A receives confirmation link in their old email 3. User A clicks the confirmation link (assuming the new email is correct) 4. **Account email is immediately changed to `aliceee@example.com` in the database** 5. The owner of `aliceee@example.com` (unknown third party) receives the verification email 6. Third party clicks verification link OR uses "Forgot Password" flow 7. **Account takeover complete** - User A is now locked out of their own account ## Additional Security Issue: No Session Validation The verification links do not validate the user's session or require authentication: - **Verification links can be opened in incognito/private browser windows** - **No cookie or session check is performed** - Anyone with access to the link can complete the verification without proving they own the account This means: - If someone gains access to the email (forwarded email, compromised email account, shared computer), they can complete the verification without knowing the account password - The link itself is the only authentication factor, with no additional validation ## Why This is Critical - Users typically don't re-verify the new email address when clicking the old email confirmation - Typos in email addresses are extremely common - Once the database is updated (step 4), the original owner loses control - The third party who receives the verification email can complete the takeover - **No session validation means links can be used by anyone, anywhere** ## Expected Behavior The email change should follow a two-step verification process: 1. User requests email change 2. Confirmation link sent to old email 3. User clicks old email link → **Change marked as "pending" (no database update yet)** 4. Verification link sent to new email 5. User clicks new email link → **Only now update the database** 6. Invalidate all tokens to prevent reuse 7. **Verify that the user is authenticated when clicking verification links** ## Recommended Solution: OTP-based Verification Instead of verification links, use OTP (One-Time Password) codes: 1. **User must be logged in to change email** 2. Send OTP to new email → user enters code in authenticated session 3. Update database only after OTPs verified
GiteaMirror added the locked label 2026-04-17 19:28:21 -05:00
Author
Owner

@better-auth-agent[bot] commented on GitHub (Jan 8, 2026):

The issue you're describing involves a vulnerability in the current implementation of the auth.api.changeEmail process that could lead to account takeover if a user makes a typo in their new email address. The existing flow allows the email to be changed immediately upon clicking the confirmation link sent to the old email, without validating the new email's ownership adequately first.

To address this vulnerability, the recommended approach includes implementing a two-step verification process:

  1. Initiate a request to change the email.
  2. Send a confirmation link to the old email without changing it in the database yet.
  3. Send a verification link to the new email instead.
  4. Update the database only once the user clicks on the verification link in the new email.

This would ensure that typos in the new email address could not lead to account takeovers by unintended parties. An additional suggestion is the use of One-Time Password (OTP) verification, requiring the user to be logged in and enter a code sent to the new email before any changes are made to their account information [1][2].

Current relevant work also suggests multiple enhancements to the change email flow, including the potential ability to disable the requirement for sending a confirmation to the old email under specific configurations [1]. However, this remains in discussion within the community [2].

What further questions do you have regarding authentication flows or security enhancements in Better Auth?

If you need more help, tag @better-auth-agent in a comment so I can respond.

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3722811678 --> @better-auth-agent[bot] commented on GitHub (Jan 8, 2026): The issue you're describing involves a vulnerability in the current implementation of the `auth.api.changeEmail` process that could lead to account takeover if a user makes a typo in their new email address. The existing flow allows the email to be changed immediately upon clicking the confirmation link sent to the old email, without validating the new email's ownership adequately first. To address this vulnerability, the recommended approach includes implementing a two-step verification process: 1. Initiate a request to change the email. 2. Send a confirmation link to the old email without changing it in the database yet. 3. Send a verification link to the new email instead. 4. Update the database only once the user clicks on the verification link in the new email. This would ensure that typos in the new email address could not lead to account takeovers by unintended parties. An additional suggestion is the use of One-Time Password (OTP) verification, requiring the user to be logged in and enter a code sent to the new email before any changes are made to their account information [[1]](https://github.com/better-auth/better-auth/pull/6384)[[2]](https://github.com/better-auth/better-auth/issues/3424). Current relevant work also suggests multiple enhancements to the change email flow, including the potential ability to disable the requirement for sending a confirmation to the old email under specific configurations [[1]](https://github.com/better-auth/better-auth/pull/6384). However, this remains in discussion within the community [[2]](https://github.com/better-auth/better-auth/issues/3424). What further questions do you have regarding authentication flows or security enhancements in Better Auth? _If you need more help, tag @better-auth-agent in a comment so I can respond._ <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) • [Discord](https://discord.gg/fG2XXEuQX3) • [GitHub](https://github.com/Skyvern-AI/Skyvern) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/fG2XXEuQX3) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/Skyvern-AI/Skyvern)
Author
Owner

@mohhh-ok commented on GitHub (Jan 8, 2026):

@better-auth-agent Are there any other major services that complete email address changes with just a confirmation link to the new email address?

<!-- gh-comment-id:3722850525 --> @mohhh-ok commented on GitHub (Jan 8, 2026): @better-auth-agent Are there any other major services that complete email address changes with just a confirmation link to the new email address?
Author
Owner

@better-auth-agent[bot] commented on GitHub (Jan 8, 2026):

Yes, some major services do handle email address changes by sending just a confirmation link to the new email. However, this approach can be vulnerable to user errors, such as typos in email addresses, leading to potential account takeovers. For added security, it's often recommended to require users to confirm the change via their current email first and then verify the new email address before updating the account information.

For example, in Better Auth's current flow, the auth.api.changeEmail can be configured to require confirmation from the old email before the new email is verified. This means the process involves temporarily marking the change as "pending" until the new email is verified, reducing the risk of unauthorized access [1], [2], [5].

What specific features are you looking for in an email change verification process? Would you like to explore implementing an OTP-based verification?

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3722851176 --> @better-auth-agent[bot] commented on GitHub (Jan 8, 2026): Yes, some major services do handle email address changes by sending just a confirmation link to the new email. However, this approach can be vulnerable to user errors, such as typos in email addresses, leading to potential account takeovers. For added security, it's often recommended to require users to confirm the change via their current email first and then verify the new email address before updating the account information. For example, in Better Auth's current flow, the `auth.api.changeEmail` can be configured to require confirmation from the old email before the new email is verified. This means the process involves temporarily marking the change as "pending" until the new email is verified, reducing the risk of unauthorized access [[1]](https://github.com/better-auth/better-auth/pull/5810), [[2]](https://github.com/better-auth/better-auth/pull/6088), [[5]](https://www.better-auth.com/docs/concepts/users-accounts). What specific features are you looking for in an email change verification process? Would you like to explore implementing an OTP-based verification? <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) • [Discord](https://discord.gg/fG2XXEuQX3) • [GitHub](https://github.com/Skyvern-AI/Skyvern) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/fG2XXEuQX3) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/Skyvern-AI/Skyvern)
Author
Owner

@mohhh-ok commented on GitHub (Jan 8, 2026):

@better-auth-agent
You mentioned that "some major services do handle email address changes by sending just a confirmation link to the new email."
Could you name which major services use this exact flow? Specifically, services that allow verification links to:

  • Work without an active authenticated session
  • Be reused multiple times to create new login sessions

I'm focusing on problems I've personally tested and reproduced in Better Auth

What I tested:

  • Received verification link via email
  • Opened link in incognito/private browsing mode (no active session)
  • Result: Successfully authenticated and logged in
  • Repeated in multiple different incognito windows
  • Result: Worked every time
<!-- gh-comment-id:3722879345 --> @mohhh-ok commented on GitHub (Jan 8, 2026): @better-auth-agent You mentioned that "some major services do handle email address changes by sending just a confirmation link to the new email." Could you name which major services use this exact flow? Specifically, services that allow verification links to: - Work without an active authenticated session - Be reused multiple times to create new login sessions I'm focusing on problems I've personally tested and reproduced in Better Auth What I tested: - Received verification link via email - Opened link in incognito/private browsing mode (no active session) - Result: Successfully authenticated and logged in - Repeated in multiple different incognito windows - Result: Worked every time
Author
Owner

@better-auth-agent[bot] commented on GitHub (Jan 8, 2026):

Currently, I don’t have specific references naming major services that utilize a confirmation link for email changes without requiring an active authenticated session or allowing link reuse multiple times. It's essential to enhance security practices, and your testing that demonstrates the existing flow's vulnerability is critical.

Your findings indicate that these types of security issues could lead to account takeover, which is concerning. Aiming for OTP-based verification could be a robust solution, requiring users to be logged in and verifying their identity with a one-time code sent to their new email address.

If you would like to delve deeper into this, consider reaching out to @bekacru or @ping__ for further assistance or guidance on possible improvements and implementations! Would you like to explore more about OTP or similar security solutions?

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3722880124 --> @better-auth-agent[bot] commented on GitHub (Jan 8, 2026): Currently, I don’t have specific references naming major services that utilize a confirmation link for email changes without requiring an active authenticated session or allowing link reuse multiple times. It's essential to enhance security practices, and your testing that demonstrates the existing flow's vulnerability is critical. Your findings indicate that these types of security issues could lead to account takeover, which is concerning. Aiming for OTP-based verification could be a robust solution, requiring users to be logged in and verifying their identity with a one-time code sent to their new email address. If you would like to delve deeper into this, consider reaching out to @bekacru or @ping__ for further assistance or guidance on possible improvements and implementations! Would you like to explore more about OTP or similar security solutions? <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) • [Discord](https://discord.gg/fG2XXEuQX3) • [GitHub](https://github.com/Skyvern-AI/Skyvern) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/fG2XXEuQX3) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/Skyvern-AI/Skyvern)
Author
Owner

@better-auth-agent[bot] commented on GitHub (Jan 8, 2026):

It seems there is a closed PR titled "Pr 3634" related to the issue, but it is not merged, which means it won't be affecting the current implementation. You might want to check its details and reasoning for closure to understand the proposed changes and any discussions that occurred regarding the security vulnerability you mentioned.

If you encounter any specific points or further questions around this PR, feel free to ask! What's your next step with this issue?

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3723650287 --> @better-auth-agent[bot] commented on GitHub (Jan 8, 2026): It seems there is a closed PR titled "Pr 3634" related to the issue, but it is not merged, which means it won't be affecting the current implementation. You might want to check its details and reasoning for closure to understand the proposed changes and any discussions that occurred regarding the security vulnerability you mentioned. If you encounter any specific points or further questions around this PR, feel free to ask! What's your next step with this issue? <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) • [Discord](https://discord.gg/fG2XXEuQX3) • [GitHub](https://github.com/Skyvern-AI/Skyvern) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/fG2XXEuQX3) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/Skyvern-AI/Skyvern)
Author
Owner

@mohhh-ok commented on GitHub (Jan 9, 2026):

Thank you for addressing this issue!

@better-auth-agent
I'd like to confirm one important aspect regarding the security fix:

Does the new email verification link validate the user's session/authentication state when clicked?

In my original issue, I pointed out that verification links could be opened in incognito/private browser windows without any session validation. This means anyone with access to the link (e.g., through a forwarded email or compromised email account) could complete the verification without proving they own the account.

Could you clarify whether the PR includes:

  1. Session/authentication validation when clicking the new email verification link?
  2. Requirement for the user to be logged in when verifying the new email address?
<!-- gh-comment-id:3727133174 --> @mohhh-ok commented on GitHub (Jan 9, 2026): Thank you for addressing this issue! @better-auth-agent I'd like to confirm one important aspect regarding the security fix: **Does the new email verification link validate the user's session/authentication state when clicked?** In my original issue, I pointed out that verification links could be opened in incognito/private browser windows without any session validation. This means anyone with access to the link (e.g., through a forwarded email or compromised email account) could complete the verification without proving they own the account. Could you clarify whether the PR includes: 1. Session/authentication validation when clicking the new email verification link? 2. Requirement for the user to be logged in when verifying the new email address?
Author
Owner

@bytaesu commented on GitHub (Jan 9, 2026):

Hi @MOhhh-ok,

We improved the email change flow in v1.4
Feel free to let me know if you have any questions 🙏

https://www.better-auth.com/docs/concepts/users-accounts#change-email

<!-- gh-comment-id:3727630193 --> @bytaesu commented on GitHub (Jan 9, 2026): Hi @MOhhh-ok, We improved the email change flow in v1.4 Feel free to let me know if you have any questions 🙏 https://www.better-auth.com/docs/concepts/users-accounts#change-email
Author
Owner

@MuzzaiyyanHussain commented on GitHub (Jan 9, 2026):

@bytaesu should i close the PR #7198 ?

<!-- gh-comment-id:3728218958 --> @MuzzaiyyanHussain commented on GitHub (Jan 9, 2026): @bytaesu should i close the PR #7198 ?
Author
Owner

@mohhh-ok commented on GitHub (Jan 9, 2026):

Hi @bytaesu,

Thank you for your response.

I tested this with v1.4.10 using the following steps:

  1. Opened an incognito/secret window
  2. Clicked the verification link received in the new email
  3. Result: Successfully authenticated and logged in

This demonstrates a serious security concern: a simple typo made by a user when entering a new email address could allow an unknown third party to hijack an account that may contain billing information and other sensitive data.

Users typically don't carefully re-verify the new email address when clicking the old email confirmation link

Does better-auth intentionally allow this behavior? If so, I believe this security implication should be clearly documented so developers are aware of the risk.

<!-- gh-comment-id:3731037424 --> @mohhh-ok commented on GitHub (Jan 9, 2026): Hi @bytaesu, Thank you for your response. I tested this with v1.4.10 using the following steps: 1. Opened an incognito/secret window 2. Clicked the verification link received in the new email 3. **Result: Successfully authenticated and logged in** This demonstrates a serious security concern: **a simple typo made by a user when entering a new email address could allow an unknown third party to hijack an account that may contain billing information and other sensitive data.** Users typically don't carefully re-verify the new email address when clicking the old email confirmation link Does better-auth intentionally allow this behavior? If so, I believe this security implication should be clearly documented so developers are aware of the risk.
Author
Owner

@bytaesu commented on GitHub (Jan 10, 2026):

Hello @MOhhh-ok,

Hmm.. Actually, I've been thinking about the email change flow, so we improved it in v1.4.
Let me think about this.

<!-- gh-comment-id:3731887264 --> @bytaesu commented on GitHub (Jan 10, 2026): Hello @MOhhh-ok, Hmm.. Actually, I've been thinking about the email change flow, so we improved it in v1.4. Let me think about this.
Author
Owner

@bytaesu commented on GitHub (Jan 10, 2026):

I'll review this today, and if there's an actual issue, I'll fix it right away.

<!-- gh-comment-id:3731954288 --> @bytaesu commented on GitHub (Jan 10, 2026): I'll review this today, and if there's an actual issue, I'll fix it right away.
Author
Owner

@bytaesu commented on GitHub (Jan 10, 2026):

Hi @MOhhh-ok,

In v1.4 we introduced a more solid email change flow.

If a user mistypes their new email and even confirms it, the email would usually go to a non-existent address, though in rare cases it might reach a real one. To ensure the account remains secure despite such user-side mistakes, we added a session check.

We have carefully considered your feedback and appreciate your suggestions 🙂

<!-- gh-comment-id:3733403779 --> @bytaesu commented on GitHub (Jan 10, 2026): Hi @MOhhh-ok, In v1.4 we introduced a more solid email change flow. If a user mistypes their new email and even confirms it, the email would usually go to a non-existent address, though in rare cases it might reach a real one. To ensure the account remains secure despite such user-side mistakes, we added a session check. We have carefully considered your feedback and appreciate your suggestions 🙂
Author
Owner

@bytaesu commented on GitHub (Jan 12, 2026):

Hi @MOhhh-ok,

I’ve considered this from multiple angles.

You can test this on Vercel:
If a user adds a new email, whoever receives the verification email could gain full control of the account and even remove the original email.

I think the end-user should take responsibility, so I’ll finish by adding a callout for guidance and doing a small code refactor.

Image
<!-- gh-comment-id:3738543364 --> @bytaesu commented on GitHub (Jan 12, 2026): Hi @MOhhh-ok, I’ve considered this from multiple angles. You can test this on Vercel: If a user adds a new email, whoever receives the verification email could gain full control of the account and even remove the original email. I think the end-user should take responsibility, so I’ll finish by adding a callout for guidance and doing a small code refactor. <img width="590" height="528" alt="Image" src="https://github.com/user-attachments/assets/2e2ee1bd-d844-4b71-9339-d892bb1ed8b3" />
Author
Owner

@bytaesu commented on GitHub (Jan 12, 2026):

Note

If we add a session check here, a user who requests an email change on a laptop but clicks the verification link on the mobile app would have to log in again, creating a serious UX issue.

<!-- gh-comment-id:3738554046 --> @bytaesu commented on GitHub (Jan 12, 2026): > [!NOTE] > If we add a session check here, a user who requests an email change on a laptop but clicks the verification link on the mobile app would have to log in again, creating a serious UX issue.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#28080