---
id: "GHSA-hwq2-v29r-p69r"
page: "https://infrastack.ai/live/GHSA-hwq2-v29r-p69r"
kind: "vulnerability"
aliases: ["GHSA-hwq2-v29r-p69r"]
title: "better-auth: Email-change links stay valid after the address changes hands"
severity: "medium"
cvss: 6.4
epss: null
exploited: false
status: "open"
category: "package"
products: [{"name": "better-auth", "fixed": ["1.7.16"], "affected": ">= 1.4.0, < 1.7.16", "ecosystem": "npm"}, {"name": "better-auth", "fixed": ["1.8.0-beta.5"], "affected": ">= 1.8.0-beta.0, < 1.8.0-beta.5", "ecosystem": "npm"}]
ecosystems: ["npm"]
tags: ["better-auth", "cwe-287", "cwe-294", "node", "package", "self-hosted"]
not_affected_if: ["changeemail-disabled", "no-email-verification", "pre-1.4.0"]
published_at: "2026-11-03T22:07:41+00:00"
first_seen_at: "2026-11-09T22:53:20+00:00"
updated_at: "2026-11-09T22:54:44+00:00"
sources: [{"source": "ghsa-repo", "url": "https://github.com/better-auth/better-auth/security/advisories/GHSA-hwq2-v29r-p69r", "first_seen_at": "2026-11-09T22:53:20+00:00"}]
exploit_sources: []
---

# better-auth: Email-change links stay valid after the address changes hands

Link for people: https://infrastack.ai/live/GHSA-hwq2-v29r-p69r (this .md is for agents)

Email-change links in better-auth did not record which user requested the change, so a link could act on whichever account later registered the old address. An attacker who controls both addresses can take over that new account and change its email to one they control.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- npm:better-auth affected >= 1.4.0, < 1.7.16 fixed 1.7.16
- npm:better-auth affected >= 1.8.0-beta.0, < 1.8.0-beta.5 fixed 1.8.0-beta.5

## How to check

- Check the installed version: `npm ls better-auth`
- Look for `user.changeEmail.enabled` set to true in the auth configuration
- Confirm `emailVerification.sendVerificationEmail` is configured

## Fix

- `better-auth` 1.4.0 up to but not including `1.7.16`: move to `1.7.16`
- `better-auth` 1.8.0-beta.0 up to but not including `1.8.0-beta.5`: move to `1.8.0-beta.5`
- Until upgraded, the advisory says to turn off user-initiated email changes; a lower `emailVerification.expiresIn` does not stop the attack

## Timeline

- 2026-11-09T22:53:20+00:00 ghsa-repo https://github.com/better-auth/better-auth/security/advisories/GHSA-hwq2-v29r-p69r

## Documents

- [advisory] Maintainer's advisory: github.com https://github.com/better-auth/better-auth/security/advisories/GHSA-hwq2-v29r-p69r

## From the sources

## Am I affected?

You are affected if you use `better-auth` 1.4.0 or later with **all** of these:

- `user.changeEmail.enabled` is turned on.
- `emailVerification.sendVerificationEmail` is configured.
- A new user can register an address after its previous owner moves to another one.

## Summary

An email change link recorded the old and new addresses, but not the user who asked for the change. If someone else registered the old address while the link was still valid, opening the link acted on that person's account.

## Impact

A user who controls the addresses involved can take over an account that later registers their released old address, using a link issued for their own account. They get a session for that account, and its email changes to an address they control. The attack needs the victim to register the released address while one of the attacker's links is still valid.

## Patches

Upgrade `better-auth` to 1.7.16, or to 1.8.0-beta.5 on the beta line.

Email verification and change links now work only for the account they were issued to. Opening a change link no longer signs the user in, and it marks the new address verified only if the current one was verified.

## Workarounds

Turn off user-initiated email changes until you upgrade. A lower `emailVerification.expiresIn` shortens the window but does not stop the attack.

## Technical details

The change link carried the old and new addresses. Without a session, Better Auth looked up the account that owned the old address at that moment, created a session for it, and changed its email. The link now carries the requesting user's ID and is rejected for any other account.

---

_Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai_
