[GH-ISSUE #2076] authClient.resetPassword does not return an error if the user email is not found #9040

Closed
opened 2026-04-13 04:19:37 -05:00 by GiteaMirror · 6 comments
Owner

Originally created by @vickon16 on GitHub (Apr 1, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/2076

    const { data: newData, error } = await authClient.forgetPassword({
      email: data.email,
      redirectTo: "/reset-password",
    });

console.log({ error}) ; // error = null ( this happens whether or not the user is in the database )

Originally created by @vickon16 on GitHub (Apr 1, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/2076 const { data: newData, error } = await authClient.forgetPassword({ email: data.email, redirectTo: "/reset-password", }); console.log({ error}) ; // error = null ( this happens whether or not the user is in the database )
GiteaMirror added the locked label 2026-04-13 04:19:37 -05:00
Author
Owner

@vickon16 commented on GitHub (Apr 1, 2025):

I found the particular line of code that is responsible for this action

Found here

Image

<!-- gh-comment-id:2770610376 --> @vickon16 commented on GitHub (Apr 1, 2025): I found the particular line of code that is responsible for this action Found [here](https://github.com/better-auth/better-auth/blob/main/packages/better-auth/src/api/routes/forget-password.ts) ![Image](https://github.com/user-attachments/assets/c4f66d7c-a82e-4b4a-934a-637a9e12aed3)
Author
Owner

@Kinfe123 commented on GitHub (Apr 2, 2025):

I think it is done intentional. it's generally not good practice to explicitly reveal to a user that an email address doesn't exist during a password reset process.

<!-- gh-comment-id:2771999955 --> @Kinfe123 commented on GitHub (Apr 2, 2025): I think it is done intentional. it's generally not good practice to explicitly reveal to a user that an email address doesn't exist during a password reset process.
Author
Owner

@vickon16 commented on GitHub (Apr 2, 2025):

I agree with you @Kinfe123, But there has to be some error response regardless, because the code returns a status = true whether or not the request was successful. Probably an error response of "invalid email" would suffice, and the main error response would be logged unto the console on the server.

I had to manually make another request to my database for this check to bypass this limitation. Which is not good because of the duplicate requests to the database.

<!-- gh-comment-id:2773339806 --> @vickon16 commented on GitHub (Apr 2, 2025): I agree with you @Kinfe123, But there has to be some error response regardless, because the code returns a status = true whether or not the request was successful. Probably an error response of "invalid email" would suffice, and the main error response would be logged unto the console on the server. I had to manually make another request to my database for this check to bypass this limitation. Which is not good because of the duplicate requests to the database.
Author
Owner

@Kinfe123 commented on GitHub (Apr 3, 2025):

so still the message is descriptive enough for any attacked to enumerate based on the flag that you given them.

<!-- gh-comment-id:2774462405 --> @Kinfe123 commented on GitHub (Apr 3, 2025): so still the message is descriptive enough for any attacked to enumerate based on the flag that you given them.
Author
Owner

@Muhammed-Rahif commented on GitHub (May 23, 2025):

I agree with you @Kinfe123, But there has to be some error response regardless, because the code returns a status = true whether or not the request was successful. Probably an error response of "invalid email" would suffice, and the main error response would be logged unto the console on the server.

I had to manually make another request to my database for this check to bypass this limitation. Which is not good because of the duplicate requests to the database.

I also thought the same, but as @Kinfe123 said, it’s actually a security best practice not to reveal if an email exists during password reset.

As per the OWASP Forgot Password Cheat Sheet, the message should be consistent and generic, as per the example from the website:

"If that email address is in our database, we will send you an email to reset your password."

Refs:

<!-- gh-comment-id:2903972664 --> @Muhammed-Rahif commented on GitHub (May 23, 2025): > I agree with you [@Kinfe123](https://github.com/Kinfe123), But there has to be some error response regardless, because the code returns a status = true whether or not the request was successful. Probably an error response of "invalid email" would suffice, and the main error response would be logged unto the console on the server. > > I had to manually make another request to my database for this check to bypass this limitation. Which is not good because of the duplicate requests to the database. I also thought the same, but as @Kinfe123 said, it’s actually a security best practice not to reveal if an email exists during password reset. As per the OWASP Forgot Password Cheat Sheet, the message should be consistent and generic, as per the [example from the website](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html#authentication-and-error-messages:~:text=ID%20or%20password.%22-,Password%20recovery,database%2C%20we%20will%20send%20you%20an%20email%20to%20reset%20your%20password.%22,-Account%20creation): > "If that email address is in our database, we will send you an email to reset your password." Refs: - [OWASP Forgot Password Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Forgot_Password_Cheat_Sheet.html#:~:text=forgot%20password%20service%3A-,Return%20a%20consistent%20message%20for%20both%20existent%20and%20non%2Dexistent%20accounts.,-Ensure%20that%20the) - [OWASP Account Enumeration Guide](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/03-Identity_Management_Testing/04-Testing_for_Account_Enumeration_and_Guessable_User_Account#:~:text=Ensure%20the%20application%20returns%20consistent%20generic%20error%20messages%20in%20response%20to%20invalid%20account%20name%2C%20password%20or%20other%20user%20credentials%20entered%20during%20the%20log%20in%20process.)
Author
Owner

@tauhid97k commented on GitHub (Oct 13, 2025):

If it were consistent, the message would be the same regardless of whether the user exists or not — but it's not. When a user does not exist, the following message is returned:

If this email exists in our system, check your email for the reset link

However, when the user does exist, the response contains only a status code 200 with no message property.
This makes it easy for anyone to infer whether a user exists in the system: if the message property is present, the user doesn't exist; if it's absent, the user does exist.

Is this really considered best practice from a security perspective?

<!-- gh-comment-id:3397081772 --> @tauhid97k commented on GitHub (Oct 13, 2025): If it were consistent, the message would be the same regardless of whether the user exists or not — but it's not. When a user does not exist, the following message is returned: > If this email exists in our system, check your email for the reset link However, when the user does exist, the response contains only a status code 200 with no message property. This makes it easy for anyone to infer whether a user exists in the system: if the message property is present, the user doesn't exist; if it's absent, the user does exist. Is this really considered best practice from a security perspective?
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#9040