ASVS 5.0 V6.4.4 says that when a user loses a multi-factor authentication factor, you must verify their identity at the same level as when they first enrolled. Recovery cannot be easier than enrollment. This is a Level 2 requirement.
Why it matters
Attackers know the lost phone flow is the weak spot. If enrollment needed a government ID check but recovery needs only an email click, the attacker simply claims to have lost the device. Social engineering of help desks works the same way.
How to implement it
Decide what your enrollment proofing was, then require an equivalent for recovery.
- If enrollment relied on a verified corporate identity, recovery should go through that identity provider or a manager and IT approval.
- If enrollment used document verification, repeat it.
- Offer backup factors (recovery codes, a second authenticator) at enrollment so fewer users need the heavy path.
- Put a delay and notification on the process: email the old address, wait a set period, and log it.
def reset_mfa(user_id: str, proofing_result):
if not proofing_result.passed or proofing_result.level < enrollment_level(user_id):
raise Forbidden("Identity proofing level too low")
revoke_factors(user_id)
revoke_all_sessions(user_id)
audit.log("mfa_reset", user_id, actor=proofing_result.verifier)
notify_all_contacts(user_id, "MFA was reset on your account")
Write down the support script too. Agents must follow it and must not override it for urgent customers.
How to test it
- Compare your enrollment evidence with what recovery asks for. Note any gap.
- Run a red team call to support from a user's real name and see whether the agent resets MFA.
- Confirm every reset creates an audit entry and a notification.
Common mistakes
- Email link only recovery for accounts enrolled with stronger proofing.
- Support agents trusting caller ID or knowledge questions.
- No notification to the user after a reset.
Quick check
Is a one time email code enough to replace a lost authenticator?
Only if enrollment was no stronger than that. Otherwise recovery is weaker than enrollment and fails V6.4.4.