ASVS 5.0 V6.4.3 requires a secure forgotten password process that does not bypass any multi-factor authentication you have enabled. If a user has MFA, resetting the password must not give them a session without it. This is a Level 2 requirement.
Why it matters
Many breaches skip the login screen and go through recovery. If a reset link alone signs the user in, then whoever controls the mailbox controls the account, and the second factor adds nothing. Mailbox takeover is far more common than device theft, so this is the path attackers prefer.
How to implement it
Treat the reset link as proof of mailbox access only, which is one factor. Then require the others.
- User asks for a reset. Respond generically (see V6.3.8) and email a single use token with a short life.
- User opens the link and sets a new password. Do not create a session yet.
- Redirect to the normal MFA challenge. Issue a session only after it passes.
- Invalidate other sessions and notify the user by email.
def complete_reset(token: str, new_password: str):
user = consume_reset_token(token) # single use, expiring
set_password(user.id, new_password)
revoke_all_sessions(user.id)
notify(user.email, "Your password was changed")
if user.mfa_enabled:
return redirect_to_mfa(user.id, purpose="post_reset") # no session yet
return start_session(user)
Make sure the same rule holds for every entry point: web, mobile API, support tooling and SSO fallback.
How to test it
- Enable MFA on a test account, run the reset flow, and confirm you land on an MFA prompt and not inside the app.
- Try calling the session endpoint directly after the reset step without completing MFA.
- Reuse and expire the reset token and confirm both fail.
- Check that existing sessions on other devices were revoked.
Common mistakes
- Auto login after a successful reset.
- Disabling MFA "because the user lost access" with no identity proofing (see V6.4.4).
- Resetting through a mobile endpoint that skips the MFA check.
- Not revoking old sessions, which keeps an attacker's earlier access alive.
Quick check
The reset link is single use and expires in 15 minutes. Is that enough?
Not on its own. It makes the link safe, but V6.4.3 also needs the MFA challenge to stay in force after the new password is set.