Files
jobtrackingapp/docs/security/MFA_RECOVERY_PROPOSAL.md
T

29 lines
4.6 KiB
Markdown

# MFA recovery and factor replacement proposal
9 November 2026. Source review at `de3d5031c8208bc3841a528ae100ec2984d68501`. Owner approval is required before changes to authentication, recovery or support permissions.
## Existing behaviour
- `TwoFactorController` issues ten hashed, one-time-use recovery codes and accepts a code after the pending sign-in credential. Code generation uses 40 random bits. The current consume path reads an unused row and then saves it. Its concurrent single-use guarantee needs a relational test.
- Setup, disabling MFA and replacing recovery codes check the current password in an authenticated session. The existing setup action can replace an enrolled TOTP factor without proving possession of that factor. The disable action clears the secret and codes. These are source findings. Account takeover and concurrent replay were not tested.
- `UsersController` is Admin-only and supports password-reset delivery. It has no admin MFA reset action. Legacy Microsoft relinking is a separate identity-binding flow and grants no MFA or mailbox recovery authority.
NIST SP 800-63B-4 describes saved codes with at least 64 random bits, one-way storage, throttling, invalidation on use and notifications. Its AAL2 recovery guidance combines independent proof or repeated identity proofing. OWASP recommends reauthentication with an enrolled factor for factor changes and treating replacement as high risk. Use this guidance to design the Jobjakt flow and verify it separately. [NIST account recovery](https://pages.nist.gov/800-63-4/sp800-63b.html#account-recovery), [OWASP MFA factor changes](https://cheatsheetseries.owasp.org/cheatsheets/Multifactor_Authentication_Cheat_Sheet.html#changing-mfa-factors)
## Proposed decision 1. Strengthen user-controlled recovery
1. Require recent account reauthentication plus an existing factor for removal, replacement or code regeneration when MFA is already enrolled. Keep first-time enrollment distinct. A local password or an active session alone cannot replace the factor.
2. Generate new saved codes with at least 64 random bits. Store only a one-way hash, show plaintext only to the reauthenticated account owner and rate-limit attempts by account and source. Accept currently valid legacy codes during a documented transition so users retain their recovery path.
3. Consume the selected code atomically with the pending challenge. One concurrent attempt may succeed. A successful code-based recovery opens a short-lived, single-use flow bound to the account and purpose. The owner proves the replacement authenticator before it replaces the old one.
4. Send an independent account notification. Revoke prior sessions and trusted devices on completed recovery. Rotate consumed or replaced recovery material. Bind the result to the owner and preserve existing OAuth and mailbox boundaries.
Acceptance requires local and applicable provider sign-in compatibility, first enrollment, ordinary TOTP, legacy and new codes, races across two challenges, wrong-owner attempts, expiry, rate limits, restart and retry behaviour. A replacement failure must leave the previously valid factor in place. No usable recovery material may appear in logs, admin responses, audit notes or URLs.
## Proposed decision 2. Escalation when the user has lost every factor
Leave escalation disabled until the owner approves a verified identity policy and the separate design. Prefer an already enrolled alternative factor. For manual escalation, support can open a request with a short reason and owner ID. A separate authorised reviewer must verify identity using the approved evidence and recently step up with their own enrolled factor. Email access by itself is insufficient. Apply two-person approval for administrator or high-risk accounts and a documented delay and cancellation window. The request expires, and the user receives independent notifications at initiation, approval and completion.
Approval can grant only an expiring, single-use re-enrolment opportunity to the verified owner. It grants no login token to staff, no access to private content and no disclosure of any old or new factor. The final binding and revocation are owner-scoped, audited and atomic. Record actor, target, reason, request ID and disposition without private evidence in ordinary logs. Cap requests and verify denial, cancellation, expiry, replay, malicious staff, last-admin protections and rollback before enabling it.
The owner must choose the identity evidence, recovery delay, roles and escalation policy before implementation. No admin-assisted recovery or private support-access route is approved by this proposal.