Skip to content

sec(auth): outstanding password-reset tokens survive a password change and expiry is not enforced in SQL #526

Description

@cristim

Summary

Outstanding password-reset tokens survive a password change, and reset-token expiry is checked only in Go, not in the SQL write.

Location (origin/main 496d9d7)

  • internal/auth/service_password.go:231 ChangePassword and internal/auth/store_postgres_credentials.go:11 UpdateUserCredentials write the new password without clearing password_reset_token / password_reset_expiry.
  • internal/auth/store_postgres_credentials.go:29-34 CompletePasswordReset matches on token and password hash but not on expiry.
  • Expiry is checked only in validateResetToken (internal/auth/service_password.go:503).

Failure scenario

  1. A user requests a reset and the token is issued.
  2. The user changes their password through the profile flow. The token stays valid.
  3. The holder of the stale token completes the reset and overwrites the newer password.

The expiry gap is a window of about one bcrypt hash, not exploitable in practice.

Context

Found in the #496 review. Related: #398, #421, #493.

Acceptance

ChangePassword and UpdateUserCredentials clear outstanding reset tokens, CompletePasswordReset enforces password_reset_expiry > NOW() in SQL, with tests for both.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions