auditing-mfa-enrollment-and-reset-abuse · git:20260903.19a7174 · 2026-09-03 · sha256 4508478e54c65c69
auditing-mfa-enrollment-and-reset-abuse git:20260903.19a7174A
Immutable. This exact content is served forever at /api/v1/blob/4508478e54c65c69.
--- name: auditing-mfa-enrollment-and-reset-abuse description: >- Audit multi-factor authentication enrollment, reset, and recovery for paths that let an attacker add their own factor or bypass the check: a first-factor session that can enroll a new authenticator without re-proving identity so a stolen password adds a second factor, an MFA reset or recovery flow guarded only by a weak signal (an email link, a knowledge question, a support request) that resets the factor to attacker control, a step-up prompt that can be skipped or is not enforced server-side on a sensitive action, backup codes that are weak, reusable, or issued without authentication, and an MFA-fatigue or push-bombing flow that approves on a single tap. Use when adding, resetting, or satisfying a second factor is the boundary between a stolen first factor and a full account takeover. The enrollment or reset request is the source, the attacker-controlled factor or bypassed check is the sink, and the missing identity proof or skippable step-up is the bug. license: MIT --- # Auditing MFA enrollment and reset abuse: the second factor is only as strong as how you enroll and reset it Multi-factor authentication assumes the attacker who has the password still cannot pass the second factor, and that assumption lives or dies in three places most audits skip: how a factor is enrolled, how it is reset or recovered, and how a step-up is enforced. If an account with only the first factor satisfied can enroll a new authenticator without re-proving identity, an attacker with a stolen password simply adds their own second factor and now passes MFA legitimately. If the reset or recovery flow is guarded only by a weak signal, an email link to an inbox the attacker controls, a knowledge question, a support request that does not verify hard, then MFA resets back to attacker control and the second factor is decorative. If a step-up prompt on a sensitive action can be skipped, or backup codes are weak, reusable, or handed out without authentication, or a push approval lands on a single tap so fatigue or bombing gets an accidental yes, the factor is bypassed rather than broken. The audit treats enrollment and reset as privileged actions that must re-prove identity, and checks that every step-up is actually enforced. You audit this by holding only the first factor and trying to add, reset, or skip the second. ## When to use - An authentication system lets users enroll a second factor, reset or recover it, use backup codes, or satisfy a step-up prompt. - Enrollment or reset may not re-prove identity, or recovery may be guarded only by a weak signal (email link, knowledge question, support request). - Step-up may be skippable, backup codes may be weak or unauthenticated, or push approval may succeed on a single tap (MFA fatigue). ## Scope check Test MFA enrollment and reset only against accounts and systems you own or are authorized to assess, with test accounts. Enrolling, resetting, and bypassing factors changes real authentication state, so use test identities and never add a factor to, reset, or take over an account that is not yours. If you can't name the authorization, stop. ## The loop 1. **Establish what enrolling and resetting a factor should require first.** Name the identity proof each privileged authentication action demands: what re-authentication enrolling a new factor requires, what resetting or recovering a factor requires, when a step-up is mandatory, and how backup codes are issued. This is the false-positive killer: a system that requires a fresh strong proof to enroll or reset a factor, enforces step-up on every sensitive action, issues strong single-use backup codes only after authentication, and requires deliberate push approval is behaving correctly. Name the intended proof, then test each path. 2. **Test factor enrollment from a first-factor-only session.** With only the password satisfied (no second factor yet passed on this session), attempt to enroll a new authenticator. Confirm the system requires a fresh, strong identity proof before adding a factor. If a stolen-password session can add its own second factor without re-proving identity, the attacker owns MFA from that point on. 3. **Test the reset and recovery flow.** Exercise every way a factor can be reset or recovered and identify what guards each: an email or SMS link, a knowledge question, a support-driven reset, a recovery code. Confirm the guard is a strong proof, not a weak signal an attacker with the first factor also controls. A reset guarded only by an email link to a takeable inbox resets the factor back to the attacker. 4. **Test step-up enforcement.** For each sensitive action that should demand a step-up (changing security settings, viewing secrets, high-value operations), attempt it without satisfying the step-up, by skipping the prompt, replaying a prior state, or calling the action directly. Confirm the step-up is enforced server-side on the action, not just shown in the UI. A skippable step-up is no step-up. 5. **Test backup codes and push approval.** Check how backup or recovery codes are generated (strength, single-use, count) and whether they can be issued or viewed without authentication. Separately, test push approval: whether repeated prompts (fatigue or bombing) can be sent and whether a single tap approves without context or number matching. Weak or unauthenticated backup codes and single-tap push are both factor bypasses. 6. **Confirm and record.** Confirm with test accounts by enrolling an attacker factor from a first-factor-only session, resetting a factor through a weak recovery guard, skipping an unenforced step-up, or approving via backup-code or push weakness, without touching real accounts. Kill the lead if enrollment and reset require a fresh strong proof, step-up is enforced server-side, backup codes are strong single-use and post-auth, and push requires deliberate approval. Record the enrollment or reset request, the attacker-controlled factor or bypassed check, and the missing identity proof or skippable step-up. ## Where MFA enrollment and reset leak - **Enrollment without re-proof.** A first-factor-only session that can add a new authenticator lets a stolen password enroll the attacker's own second factor. - **Weak reset or recovery guard.** A factor reset guarded only by an email link, a knowledge question, or a soft support check resets MFA back to attacker control. - **Skippable step-up.** A sensitive action that shows a step-up prompt but does not enforce it server-side is reachable without the second factor. - **Weak or unauthenticated backup codes.** Backup or recovery codes that are guessable, reusable, or issued without authentication are a standing bypass of the factor. - **Single-tap push and MFA fatigue.** A push that approves on one tap, with no number matching or context and no limit on repeated prompts, lets fatigue or bombing get an accidental approval. ## Worked example (a confirm and a kill) > **Confirm.** After entering a valid password, but before satisfying any second factor, the account settings > page lets the session enroll a new authenticator app and does not require the existing second factor or any > fresh proof. On a test account, an attacker holding only the stolen password enrolls their own authenticator > and from then on passes MFA legitimately, locking the real user's factor out of the decision. **Confirmed** > attacker factor enrollment from a first-factor-only session, `high`, remediation = require a fresh strong proof > (the existing second factor, or full re-authentication) before enrolling, changing, or removing any > authenticator. > > **Kill.** Enrolling, changing, or removing a factor requires the existing second factor or full > re-authentication; reset and recovery are guarded by a strong proof, not a weak email or knowledge signal; > every sensitive action enforces step-up server-side; backup codes are strong, single-use, and issued only > after authentication; and push requires number matching with limits on repeated prompts. A first-factor-only > session cannot add a factor, a weak recovery signal does not reset one, and a step-up cannot be skipped. > **Killed**, `kill_reason` = "enrollment and reset require a fresh strong proof, step-up is enforced server-side, > backup codes are strong single-use post-auth, and push needs deliberate approval; a stolen first factor cannot > add, reset, or bypass the second." ## Rationalizations to reject - *"They already entered the password."* → The password is the factor assumed stolen; enrolling or resetting a second factor must re-prove identity beyond the password, or MFA protects nothing against a credential leak. - *"Recovery has to be easy."* → Easy recovery guarded by a signal the attacker also controls is an attacker recovery path; require a strong proof to reset a factor even at the cost of some friction. - *"The step-up prompt appears."* → A prompt shown in the UI is not enforcement; confirm the server rejects the sensitive action when the step-up is not satisfied, including on a direct call. - *"Backup codes are for emergencies."* → Emergency codes are full bypasses; if they are weak, reusable, or viewable without authentication, the attacker uses them as the primary path. - *"The user approved the push."* → A single-tap approval under a flood of prompts is not consent; require number matching and rate-limit prompts so fatigue and bombing cannot harvest an accidental yes. ## Executing this in practice You need the enrollment flow's re-authentication requirement, every reset and recovery path and its guard, which actions demand a step-up and how it is enforced, and how backup codes and push approvals work. With test accounts, hold only the first factor and try to enroll a new factor, reset an existing one, skip a step-up, and approve via backup code or push. Reading the enrollment and reset handling shows the intended proof; an attacker factor added or a check bypassed from a first-factor-only session shows what the proof fails to require. ## Related - `auditing-account-recovery-and-reset-trust` - the account-level recovery flow; MFA reset is a specific factor reset that shares the weak-recovery-signal failure mode. - `auditing-webauthn-and-passkey-flows` - the enrollment and step-up mechanics for passkeys; adding a phishing-resistant factor still depends on proving identity at enrollment. - `auditing-session-lifecycle-and-fixation` - the session that enrollment and step-up act on; whether a factor change re-issues or elevates the session is shared ground. - `reviewing-rate-limiting-and-abuse-controls` - push-bombing and code-guessing are rate-limit failures; that skill covers the abuse controls this one depends on. - [FINDING-SCHEMA.md](../../FINDING-SCHEMA.md) - source = the enrollment or reset request, sink = the attacker-controlled factor or bypassed check, evidence = the missing identity proof or skippable step-up.