# Password Reset Token Prediction via UUID1 Timestamp Leakage

Language: Python
Severity: Critical
CWE: CWE-338

## Source
9

## Flow
9-11

## Sink
11

## Vulnerable Code
```python
import uuid
import time
from flask import Flask, request, jsonify
app = Flask(__name__)
reset_tokens = {}
@app.route('/api/v2/account/recovery/initiate', methods=['POST'])
def initiate_account_recovery():
    user_email = request.json.get('email')
    recovery_token = str(uuid.uuid1())
    reset_tokens[recovery_token] = {'email': user_email, 'timestamp': time.time()}
    send_recovery_email(user_email, recovery_token)
    return jsonify({'status': 'recovery_initiated', 'token_hint': recovery_token[:8]})
def send_recovery_email(email, token):
    print(f'Recovery link: https://app.example.com/reset?token={token}')
```

## Explanation

The password reset token is generated using uuid.uuid1() which incorporates the MAC address and timestamp, making it predictable. An attacker who receives one reset token can extract the timestamp and MAC address, then generate tokens for other users by predicting the timestamp when their reset was requested. The token hint exposure in the response and full token leak in logs further aids attackers.

## Remediation

The fix replaces uuid.uuid1() with secrets.token_urlsafe(32), which generates a cryptographically secure random token with 256 bits of entropy that cannot be predicted. Additionally, the token hint was removed from the API response and the full token is no longer logged, preventing information leakage that could aid attackers.

## Secure Code
```python
import secrets
import time
from flask import Flask, request, jsonify
app = Flask(__name__)
reset_tokens = {}
@app.route('/api/v2/account/recovery/initiate', methods=['POST'])
def initiate_account_recovery():
    user_email = request.json.get('email')
    recovery_token = secrets.token_urlsafe(32)
    reset_tokens[recovery_token] = {'email': user_email, 'timestamp': time.time()}
    send_recovery_email(user_email, recovery_token)
    return jsonify({'status': 'recovery_initiated'})
def send_recovery_email(email, token):
    print(f'Recovery email sent to {email}')
```
