Last reviewed: October 31, 2026 (Asia/Shanghai). Sources fetched October 30, 2026 UTC.

Direct answer

Review password-reset changes in coding-agent patches by tracing the entire recovery grant: who can request it, which account it authorizes, where the email link points, when it expires, how successful redemption prevents reuse, and what happens to existing sessions. Require a valid recovery grant before any password change. Test two simultaneous submissions of the same grant through the real persistence layer; sequential replay tests alone cannot establish single-use behavior under concurrency.

The OWASP Forgot Password Cheat Sheet calls for consistent request responses, secure expiring single-use tokens, trusted HTTPS reset URLs, and a deliberate session-invalidation policy. A working email and a successful form submission cover only part of that contract.

Consider an agent-written handler that checks used_at, changes the password, then marks the token used. Two workers can both pass the first check before either writes. The review must establish one successful credential transition across workers, including retries and failures between writes.

Who this is for

Use this guide when a coding agent changes forgot-password routes, email templates, token helpers, password-confirmation forms, user models, background mail delivery, or post-reset session handling. It covers application-owned password recovery through an established email address. MFA recovery, support-assisted identity proofing, and identity-provider account recovery require their own policies.

The example policy permits one successful redemption per grant, invalidates outstanding reset grants and existing application sessions after success, and requires ordinary sign-in afterward. Those are explicit acceptance criteria for this workflow. Confirm the appropriate recovery policy with the identity owner before implementing it.

Key takeaways

  • A reset request must not reveal account existence or change credentials.
  • Bind the grant to an account and recovery purpose; a submitted account ID cannot redirect its authority.
  • Use the framework’s maintained token mechanism and password-setting API.
  • Make validation, credential replacement, and grant invalidation consistent under concurrency.
  • Generate email links from trusted origin configuration and prevent token leakage.
  • Test existing sessions separately from the new password.

Sources checked

Three primary public references were fetched successfully on October 30, 2026 UTC:

  • OWASP: Forgot Password Cheat Sheet supports request privacy, abuse controls, token lifetime and single use, recovery-link construction, password policy, notifications, and post-reset login decisions.
  • Django: Using the authentication system documents password-reset eligibility, its email-timing warning, reset-confirmation behavior, and password-based session invalidation. The fetched canonical reference is versioned 6.1; match the documentation to the installed release when reviewing a project.
  • OWASP: Session Management Cheat Sheet supports server-side session invalidation, session renewal around authentication changes, sensitive-page caching controls, and credential-safe logging.

These maintained technical references support an evergreen engineering task. The transaction outline and test matrix below are recommended acceptance checks derived from their requirements. They are not reported application test results or a newly disclosed incident.

Contract details to verify

Separate request acceptance from recovery authority

An unauthenticated request supplies an account lookup value. It does not prove ownership. Use the same public message and response shape for eligible and ineligible addresses, and review timing as well as wording. OWASP recommends consistent response timing; asynchronous delivery can help keep email transmission off the response path, but it does not automatically remove every existence-dependent branch.

Django documents a useful eligibility boundary: its reset view sends mail only for an existing active user with a usable password, while other cases still reach the completion page. A patch that enables password recovery for an externally authenticated account can change the account’s authentication model. Preserve the intended eligibility rule.

Rate-limit reset requests and token guesses, with controls that address repeated requests against one account as well as abusive sources. Throttle recovery attempts without locking the victim out of ordinary login merely because somebody requested a reset. Send recovery mail to the account’s established recovery address, never to an alternate delivery address supplied with the request.

Define the grant’s scope and lifetime

Record the following decisions before approving token code:

BoundaryRequired decision
AccountTrusted account identity associated with the grant
PurposePassword recovery only; no general login or MFA-reset authority
ExpiryExplicit lifetime, clock source, and expiration boundary
ReuseHow success makes the grant unacceptable to every worker
SupersessionWhether a new request invalidates older unredeemed grants
SuccessPassword update, outstanding-grant policy, session policy, and notification

Prefer the framework’s maintained reset mechanism. For a custom opaque-token design, use a cryptographically secure random secret and protect its stored representation. A one-way verifier is a useful engineering choice so a read-only token-table disclosure does not immediately expose redeemable secrets. Bind the record to the account, recovery purpose, expiry, and consumption state.

For a framework-provided token, review its documented invalidation mechanism rather than assuming it uses a token table. A signed token’s integrity and expiry still leave the separate questions of replay, concurrent redemption, and invalidation after account changes.

Make the credential transition indivisible

For a custom database-backed grant, the following is a transaction design to adapt and test:

  1. Validate the proposed password against the application’s normal policy without changing account state.
  2. Start a transaction and serialize competing redemptions for the affected account and grant using the database’s appropriate locking or conditional-update mechanism.
  3. Recheck account binding, recovery purpose, expiry, unused state, and any credential-version rule against authoritative state inside that protected transition.
  4. Set the password through the normal password API, consume the grant, and invalidate other outstanding grants according to the example policy.
  5. Commit those changes together. Arrange the success notification through the application’s reliable post-commit delivery mechanism.

The required invariant is that competing valid submissions cannot both commit password replacements. A lock in one web process cannot coordinate other processes. A conditional update is useful only if its result and the password update participate in the same protected transition. For a framework-generated token, inspect the integration’s equivalent account-level serialization and revalidation behavior; the documentation’s phrase “one-time use” does not by itself prove a custom wrapper’s concurrency behavior.

Keep email delivery outside the credential transaction’s success decision. If delivery fails after the password changed, retry the notification under the application’s delivery policy without reopening the consumed grant. If the credential transaction rolls back, it must not leave a consumed grant paired with an unchanged password. These are implementation recommendations, not guarantees supplied by the cited frameworks.

OWASP warns against constructing reset URLs from an untrusted Host header. Use a configured HTTPS origin or a validated trusted-domain mapping. In a multi-tenant product, derive that mapping from trusted tenant configuration rather than a caller’s requested destination. Test forwarded-host handling through the real proxy.

Apply Referrer-Policy: no-referrer on recovery pages, as OWASP recommends. Exclude raw reset URLs from analytics, error reports, access logs, and agent transcripts. Review third-party resources and sensitive-page cache policy as possible disclosure paths. Opening a link may validate the grant or establish narrowly scoped recovery state; it must not itself change the password or grant ordinary account access. In this example, final consumption accompanies the successful password submission, so a mail scanner’s preview does not spend the grant.

If the flow establishes a recovery cookie or session, review the password-submission route with the site’s CSRF review workflow . A recovery session should authorize only the intended recovery operation.

Verify session invalidation as its own outcome

OWASP recommends ordinary login after reset and either offering session invalidation or doing it automatically. This guide’s example chooses automatic invalidation. Inventory application sessions, remember-me credentials, refresh tokens, and any other credentials the product promises to revoke. Password replacement alone cannot establish revocation across independent stores or services.

The Django authentication reference explains that compatible user models include a password-derived authentication hash in sessions and check it on subsequent requests. It also describes preserving the current session during an authenticated password change. Review that distinction before copying a password-change helper into an unauthenticated recovery flow. Django’s reset-confirmation view defaults post_reset_login to False.

For distributed revocation, specify how each consumer observes invalidation and what access is permitted while it is pending. Test the old credential against a protected endpoint after reset; deleting a cookie in the recovery browser does not invalidate a stolen copy elsewhere. A reset must also preserve the product’s MFA requirements and recovery-contact policy.

Happy-path operator workflow

Freeze the agent revision and trace request, mail generation, confirmation, credential update, and session checks. Use disposable accounts and a local mail sink. Capture the link privately, verify its trusted origin, submit a compliant new password through the real route, and confirm that the old password fails while the new password works through ordinary sign-in. Check the selected session policy and confirm that the notification contains no password.

Retain the revision, framework version, recovery-policy version, fixture label, result class, and credential-transition count. Keep tokens, passwords, session cookies, raw mail bodies, and full recovery URLs out of shared evidence.

Prove the boundary with a redemption matrix

Exercise the real database and middleware. For concurrent cases, use two independently valid recovery clients and a controlled synchronization point so both submissions reach the critical transition. An unrelated CSRF failure must not be mistaken for proof of single-use enforcement. The site’s race-condition testing guide explains how to retain reproducible ordering evidence.

FixtureRequired observation under the example policy
Eligible account and valid grantOne password transition; ordinary sign-in required
Unknown, inactive, or externally authenticated ineligible accountSame public request response; no password or eligibility change
Altered grant or another account ID submitted with itNo unauthorized account mutation
Expired grant at the configured boundaryRejected; password and consumption state unchanged
Successful grant submitted againNo second password transition
Same grant submitted concurrently with two different new passwordsExactly one commit; losing request cannot overwrite it
Two different outstanding grants redeemed concurrentlyOne succeeds; the other fails under the invalidate-all-grants policy
Failure injected between password write and grant consumptionTransaction rolls back both changes
Notification delivery fails after commitPassword remains changed; grant stays consumed; delivery can retry
Host or forwarded-host altered during issuanceMail contains only the configured trusted recovery origin
Recovery link opened by a preview clientNo password change, ordinary login, or final grant consumption
Session created before reset reused afterwardProtected request denied under the selected revocation policy

Use an injectable clock for expiry cases. Inspect durable state and the final accepted password after both competing requests complete. A pair of response codes alone cannot show which writes committed. Compare request-timing distributions for known and unknown accounts over repeated controlled samples; one matching response time proves little.

Error-path operator workflow

For malformed, expired, consumed, or unbound grants, return a controlled generic recovery failure before changing credentials. If authoritative recovery state is unavailable, stop the credential transition. Do not fall back to an unchecked token or a user ID from the form.

If the response is lost after a successful commit, a repeat must find the grant unusable. Guide the user to ordinary sign-in or a fresh recovery request without repeating the credential update. If a negative fixture changes a password, preserves forbidden access, or leaks a usable link, block the patch, preserve sanitized evidence, and repair that boundary before rerunning the matrix.

Failure modes

Identical wording hides different behavior. Status codes, redirect targets, eligibility changes, and email-dependent timing can still disclose account information.

Token validation and consumption surround separate writes. Two workers or a mid-write failure can violate single use. Verify the complete credential transition.

A password-reset helper becomes a general recovery bypass. Preserve external-authentication eligibility, MFA requirements, and restrictions on changing recovery contacts.

The new password works, so recovery is declared complete. Old sessions or independent refresh credentials may still authorize access. Exercise those consumers explicitly.

FAQ

Does a signed JWT make a reset grant single use?

Signature verification establishes integrity under the selected key and policy. It does not record redemption. The design still needs an authoritative consumption or account-state rule that remains correct under concurrency.

Choose and document that policy. Revoking on every unauthenticated request can let another person invalidate a legitimate user’s link repeatedly. Regardless of issuance policy, this example invalidates all outstanding grants after a successful password reset.

Does a password reset recover a compromised account completely?

It may leave changed recovery contacts, unauthorized MFA methods, or independent sessions in place. OWASP treats suspected-compromise recovery as a broader process. Route that case through the reviewed account-recovery policy.

Reader next step

Choose one agent-written recovery handler. Write its account, purpose, expiry, redemption, and session contract, then add a concurrent same-grant test and an old-session test through the real stack. Approve the patch when a legitimate user can recover and the recorded negative cases cannot overwrite credentials, reuse authority, or retain access the policy promises to revoke.