mediumCWE-640A07:2021

Password Reset Token Without Expiry

Password reset links that never expire stay valid indefinitely — an old email in a breach gives attackers a permanent account takeover path.

How It Works

If a password reset token has no expiry, it stays valid forever in your database. Old emails in a compromised inbox, forwarded reset emails, or tokens exfiltrated from logs all become permanent account takeover vectors. The token should be single-use and expire within 1-2 hours.

Vulnerable Code
// BAD: reset token stored without expiry
async function createResetToken(userId: string) {
  const token = crypto.randomBytes(32).toString('hex');
  await db.passwordResets.create({ userId, token }); // no expiresAt!
  return token;
}
Secure Code
// GOOD: token expires in 1 hour and is deleted after use
async function createResetToken(userId: string) {
  const token = crypto.randomBytes(32).toString('hex');
  const expiresAt = new Date(Date.now() + 60 * 60 * 1000); // 1 hour
  await db.passwordResets.create({ userId, token, expiresAt });
  return token;
}
// In the reset handler: verify expiresAt > now AND delete token after use

Real-World Example

Password reset tokens without expiry were flagged in numerous HackerOne bug bounty reports as account takeover vulnerabilities. If a user's inbox is compromised months after requesting a reset, the old link still works.

How to Prevent It

  • Set a 1-hour expiry on all password reset tokens
  • Delete the token immediately after it's used (single-use)
  • Invalidate all existing reset tokens when a new one is requested
  • Also invalidate all active sessions when a password is successfully reset

Affected Technologies

Node.js

Data Hogo detects this vulnerability automatically.

Scan Your Repo Free

Related Vulnerabilities