Skip to main content

Documentation Index

Fetch the complete documentation index at: https://guide.codepure.com/llms.txt

Use this file to discover all available pages before exploring further.

Overview

This vulnerability occurs when the mechanism for users to recover or reset forgotten passwords is insecure. Common weaknesses include:
  • Predictable Reset Tokens: Generating password reset tokens that are short, based on guessable information (like username or timestamp), or have insufficient randomness, allowing attackers to predict or brute-force them.
  • Token Transmission over Insecure Channels: Sending reset tokens or temporary passwords via unencrypted email (HTTP links) or SMS.
  • Information Leakage: The recovery process reveals whether a username or email exists in the system (“User Enumeration”).
  • Weak Security Questions: Relying on easily guessable or publicly available answers to “secret questions”.
  • Token Reuse/No Expiry: Reset tokens do not expire or can be reused after the password has been reset.
  • Not Invalidating Other Sessions: Failing to log the user out of other active sessions after a password reset. 🤔❓🔑

Business Impact

Weak password recovery mechanisms provide a direct path for attackers to compromise user accounts:
  • Account Takeover: Attackers can guess or predict reset tokens/answers, allowing them to set a new password and take over the account.
  • User Enumeration: Attackers can determine valid usernames or emails registered with the service.
  • Loss of Trust: Users rely on secure recovery processes; flaws severely damage trust.

Reference Details

CWE ID: CWE-640 OWASP Top 10 (2021): A07:2021 - Identification and Authentication Failures Severity: High to Critical

Framework-Specific Analysis and Remediation

Password recovery typically involves generating a secure, random, single-use, time-limited token, sending it to the user via a secure channel (usually email with an HTTPS link), and requiring the user to present that token to set a new password. Frameworks often provide built-in modules for this. Key Remediation Principles:
  1. Use Strong Tokens: Generate long (e.g., 32+ bytes), cryptographically random tokens (CSPRNG). Store a hash of the token in the database, not the token itself.
  2. Set Token Expiry: Tokens should expire after a short period (e.g., 15-60 minutes). Store the expiry timestamp with the token hash.
  3. Single Use: Invalidate the token immediately after it is successfully used.
  4. Secure Transmission: Send reset links via email using HTTPS URLs. Avoid sending temporary passwords directly.
  5. Avoid User Enumeration: Respond with a generic message like “If an account exists for this email, a reset link has been sent” regardless of whether the email was found.
  6. Avoid Weak Security Questions: Do not use easily guessable questions. Prefer token-based email/SMS reset.
  7. Invalidate Sessions: Log the user out of all other active sessions upon successful password reset.

Framework Context

Using Django’s built-in PasswordResetView and associated forms/tokens, or custom Flask logic.

Vulnerable Scenario 1: Predictable Token Generation (Custom)

# accounts/utils.py
import hashlib
import time
from django.conf import settings

def generate_weak_reset_token(user):
    # DANGEROUS: Token based on predictable data (user ID, timestamp)
    # and a weak hash (MD5) without strong randomness.
    timestamp = int(time.time())
    data_to_hash = f"{user.id}:{user.password}:{timestamp}:{settings.SECRET_KEY}"
    token = hashlib.md5(data_to_hash.encode()).hexdigest()
    # Assume token and timestamp stored temporarily
    return token, timestamp

Vulnerable Scenario 2: Token Sent Over HTTP

The email template for the password reset link uses an http:// URL.
Please click here to reset your password:
<a href="http://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}">Reset Link</a>

Mitigation and Best Practices

  • Django: Use the built-in authentication views (PasswordResetView, PasswordResetConfirmView, etc.) which rely on django.contrib.auth.tokens.PasswordResetTokenGenerator. This generator creates secure, time-limited, single-use tokens based on user state and the application’s SECRET_KEY.
  • Ensure email templates use https:// links.

Secure Code Example

# urls.py (Using Django's built-in views)
from django.contrib.auth import views as auth_views

urlpatterns = [
    # SECURE: Use Django's built-in password reset flow.
    path('reset_password/',
         auth_views.PasswordResetView.as_view(template_name="accounts/password_reset.html"),
         name="reset_password"),
    path('reset_password/sent/',
         auth_views.PasswordResetDoneView.as_view(template_name="accounts/password_reset_sent.html"),
         name="password_reset_done"),
    path('reset/<uidb64>/<token>/',
         auth_views.PasswordResetConfirmView.as_view(template_name="accounts/password_reset_form.html"),
         name="password_reset_confirm"),
    path('reset_password/complete/',
         auth_views.PasswordResetCompleteView.as_view(template_name="accounts/password_reset_done.html"),
         name="password_reset_complete"),
]
Please click here to reset your password:
<a href="https://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}">Reset Link</a>

Testing Strategy

Review the token generation logic. Is it using cryptographically secure randomness (secrets.token_urlsafe) or a robust framework mechanism (like Django’s)? Check token length and expiry. Attempt to reuse a reset token after successfully resetting the password. Check the reset link email for http:// vs https://. Test the “forgot password” form with known and unknown email addresses; verify the response message is generic and doesn’t reveal account existence.