Back to blog
technicalauthenticationvulnerabilities

Password reset: the 7 mistakes that open up your accounts

Published on 2026-06-267 min readCleanIssue

The weak link in authentication

You've polished your login: bcrypt-hashed passwords, MFA available, rate limiting in place. But the "forgot password" flow bypasses all of it by design: it allows taking over an account without knowing the password. That's why attackers test it first — and why we do too.

Here are the 7 mistakes we encounter most often, from most severe to most subtle.

1. Predictable or short token

A reset token built from a timestamp, a base64-encoded user ID, or a UUID v1 (which embeds the timestamp and MAC address) can be guessed or brute-forced. You need at least 128 bits of entropy from a cryptographic generator (crypto.randomBytes, not Math.random()).

2. Token without expiration

A reset link sent 6 months ago that still works is one more live link sitting in a compromised mailbox. Recommended maximum lifetime: 15 to 60 minutes.

3. Token not invalidated after use

The token must be single-use. If it stays valid after the password change, an attacker who intercepted the email can re-reset the account afterwards. Same requirement: invalidate all previous tokens when a new one is requested.

4. Host header injection

The most elegant mistake. If your backend builds the reset link from the request's Host header, an attacker requests a reset for the victim while sending Host: attacker.com. The victim receives a legitimate email… with a link pointing to the attacker's domain, token included. The link must be built from a base URL defined in configuration, never from the request.

5. User enumeration

"No account associated with this address" vs "Email sent": this difference in messaging lets anyone build a list of your SaaS customers. Identical response in both cases — response time included.

6. Sessions not revoked after reset

The scenario: an attacker already has an active session on the account (leaked password, stolen session). The victim changes their password to kick them out… but the attacker's session stays valid. Any password change must revoke all existing sessions and refresh tokens.

7. No rate limiting on reset requests

Without limits, the feature becomes a spam cannon aimed at your users — and a mass-testing tool for mistakes 1 through 5.

Checklist

  • [ ] Token ≥ 128 bits of cryptographic entropy, stored hashed in the database
  • [ ] Expiration ≤ 60 minutes, single-use, previous tokens invalidated
  • [ ] Reset URL built from configuration, not from the Host header
  • [ ] Identical response whether the email exists or not
  • [ ] All sessions revoked after a password change
  • [ ] Rate limiting per IP and per target account
  • [ ] Notification sent to the user after any effective change
  • These 7 points are part of the systematic checks in our First Review: 48 hours, real-world conditions, no access to your code required.

    Related articles

    Three adjacent analyses to keep exploring the same attack surface.

    Sources

    Written by CleanIssue
    Reviewed on 2026-06-26

    Related services

    If this topic maps to a real risk in your stack, these are the most relevant CleanIssue audits.

    Need an external review of your HR SaaS?

    Share your product, stack, and client context. We will come back with the right review scope.

    Discuss your audit