Risk-Based Step-Up & Account Recovery · Chapter 4 of 5
Account recovery as the softest door — hardening it
Recovery bypasses every factor by design. Map its paths, rank the evidence each accepts, add delay and notification, and stop recovery from downgrading strong accounts.
Every authentication system has a door that opens without the usual keys: account recovery. It exists because people lose phones, forget passwords and break security keys. It is, by construction, a path that grants access to someone who cannot present the normal factors. That makes it the natural target for an attacker who cannot beat the front door. If your login requires a passkey but recovery accepts an SMS code, your real security level is an SMS code.
At Tidewater Mutual, Marisol’s threat model from series 3 ranked recovery as the highest residual risk. This chapter walks through how she hardened it without making recovery impossible for the members who genuinely need it.
Map every path
The first job is discovery, because recovery paths multiply quietly. Tidewater found six: email link for password reset; SMS code for password reset; “I lost my phone” flow to remove the second factor; in-branch identity check; phone support with knowledge questions; and an old API endpoint used by a retired mobile app that still reset passwords with only a date of birth. That last one had not appeared in any design document for four years. Each path is a door, and the account is only as strong as the weakest one that is still open.
Rank the evidence
Recovery paths accept different kinds of evidence, and they are not equivalent. Tidewater ranks them. Strongest: a remaining enrolled passkey or a pre-generated recovery code the member stored offline. Strong: in-person check of a government document against the member record. Moderate: control of the registered email and the registered phone together. Weak: control of either one alone. Very weak: knowledge questions, dates of birth, last four digits of a card — facts that are routinely available from breaches and social media.
The rule that follows is: recovery must not accept evidence weaker than the factors it replaces, without compensating controls. If Dorian has a passkey and a TOTP app, a reset by SMS code alone is a downgrade, and it is allowed only through the delayed, notified, restricted path below. If a member only ever had a password and SMS, an SMS-based recovery is not a downgrade. Account strength becomes an input to recovery policy, exactly as action sensitivity was an input to step-up policy.
Delay, notify, restrict
For any recovery that downgrades the account, Tidewater applies three compensating controls. Delay: the reset is scheduled, not immediate — 24 hours for moderate evidence, 72 hours for weak. Notify: every registered channel — email, push to every enrolled device, SMS to the old number — receives a message describing the request, with a one-tap “This wasn’t me” that cancels it and locks recovery. Restrict: after completion, the account runs in a restricted mode for seven days, during which control actions such as new payees, contact changes and limit increases are blocked or require branch verification.
Each control targets a different part of the attacker’s plan. The delay converts a smash-and-grab into a race the owner can win. The notification reaches the owner on channels the attacker has not compromised; a SIM-swapper controls the phone number but rarely the email inbox and the enrolled app at the same time. The restriction limits the value of a recovery that slips through: the attacker gets in, but cannot add a mule payee before the owner notices.
Attacker view
Attacker on the recovery path
- Finds the forgotten endpoint that resets on date of birth.
- SIM-swaps the number, then uses SMS recovery to drop the passkey.
- Times the request for a holiday weekend.
- Adds a payee within minutes of regaining access.
Defender view
Defender controls
- Inventory and close undocumented recovery routes.
- Rank evidence; SMS alone cannot downgrade a passkey account.
- Delay with notifications to every channel and a cancel link.
- Restricted mode blocks control actions for seven days.
Recovery codes, done right
Recovery codes are the cheapest strong evidence available. At enrolment of a strong factor, Tidewater generates ten single-use codes of ten base32 characters each — about 50 bits per code — shows them once, and stores only salted hashes. Using a code consumes it, notifies the member and immediately prompts them to enrol a replacement factor. Members who keep the codes in a password manager or a drawer can recover instantly and fully, without delay, because the evidence matches the strength of what they lost.
// Store recovery codes like passwords: hashed, single use.
const codes = Array.from({ length: 10 }, () => base32(randomBytes(7)).slice(0, 10));
await db.recoveryCodes.insertMany(codes.map((c) => ({ user, hash: await argon2(c), used: false })));
return codes; // shown once, never retrievable againSupport is a recovery path
A support agent who can reset an account is a recovery mechanism with a human interface, and humans can be persuaded. Agent tools should enforce the same evidence ranking and delays as the self-service flow: the agent can start a recovery, but cannot skip the cooling-off period or the notifications, and cannot reset a passkey account on knowledge alone. Chapter 5 explores the social engineering side in depth.
| Threat | Inherent | Mitigation | Residual |
|---|---|---|---|
| Legacy endpoint resets password on date of birth | Critical | Path inventory; endpoint removed and monitored for calls | Low |
| SIM swap followed by SMS-only recovery | High | Evidence ranking, 72 h delay, notifications to email and app, restricted mode | Medium |
| Owner stranded after losing every factor | Medium | Recovery codes; branch path with document check | Low |
app.post("/recover", async (req) => {if (await sms.verify(req.phone, req.code)) {await users.resetFactors(req.userId);return session.create(req.userId);}});
// bench check
0/3 correct · 0 answered
1. A member has a passkey and TOTP. Someone requests recovery with only an SMS code. What should happen?
2. What is the main purpose of notifying every registered channel during recovery?
3. Why can a valid recovery code restore full access without a delay?