domain: password-reset job retries mint additional valid reset tokens #59
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
rosa/vernier#59
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found during a code review of the
domaincrate.Location:
crates/domain/src/services.rs:292(run_password_reset)Severity: Security / Correctness
Problem
run_password_resetinserts a password-reset confirmation, then enqueues the email as a separate call; the apalis job wrapper maps every failure to Retryable, and prior reset tokens are not deleted when a new one is minted. A mailer-enqueue failure after the insert re-runs the whole flow and mints an additional simultaneously-valid token per retry.Failure scenario
create_password_reset_confirmationsucceeds, the mailer enqueue fails transiently, the job retries, and a second (and third) valid 30-minute reset token accumulates for the same user, widening the reset window.Suggested fix
Delete prior reset tokens before minting a new one (or make insert+enqueue transactional/idempotent), so at most one reset token is valid at a time.
Verified during triage by code inspection: the queued reset flow inserts a confirmation, then enqueues the email as a second fallible call; the apalis handler maps every failure to a retryable error; and the confirmation insert is a plain INSERT that never clears prior password-reset tokens. A transient mailer-enqueue failure therefore re-runs the whole flow and mints an additional simultaneously-valid 30-minute token on each retry.
Agent Brief
Category: bug
Summary: Guarantee at most one valid password-reset token per user, so job retries converge instead of accumulating valid tokens
Current behavior:
run_password_resetlooks up the user, inserts a new password-reset confirmation, and then enqueues the reset email. The apalis job wrapper treats every failure as retryable. Prior password-reset confirmations for the user are never removed. If the mailer enqueue fails after the insert, the retry mints another valid token — each retry widens the window of simultaneously-valid reset links.Desired behavior:
Minting a password-reset confirmation invalidates any prior password-reset confirmations for that user, so at most one reset link is valid per user at any time. A retried job converges: however many times it runs, exactly one valid token exists afterwards, and it is the one whose link was (eventually) emailed. Confirmations for other action types (email confirmation) are untouched. The lookup-miss behavior (unknown email quietly succeeds) is unchanged.
Key interfaces:
ConfirmationAction::PasswordResetis the discriminator — only rows with that action type are displaced.Acceptance criteria:
run_password_resettwice for the same user (simulating a retry) leaves exactly one valid password-reset confirmation.cimise task passes.Out of scope: