{"title":"Password Reset Token Prediction via UUID1 Timestamp Leakage","language":"Python","severity":"Critical","cwe":"CWE-338","source_lines":[9],"flow_lines":[9,11],"sink_lines":[11],"vulnerable_code":"import uuid\nimport time\nfrom flask import Flask, request, jsonify\napp = Flask(__name__)\nreset_tokens = {}\n@app.route('/api/v2/account/recovery/initiate', methods=['POST'])\ndef initiate_account_recovery():\n    user_email = request.json.get('email')\n    recovery_token = str(uuid.uuid1())\n    reset_tokens[recovery_token] = {'email': user_email, 'timestamp': time.time()}\n    send_recovery_email(user_email, recovery_token)\n    return jsonify({'status': 'recovery_initiated', 'token_hint': recovery_token[:8]})\ndef send_recovery_email(email, token):\n    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":"import secrets\nimport time\nfrom flask import Flask, request, jsonify\napp = Flask(__name__)\nreset_tokens = {}\n@app.route('/api/v2/account/recovery/initiate', methods=['POST'])\ndef initiate_account_recovery():\n    user_email = request.json.get('email')\n    recovery_token = secrets.token_urlsafe(32)\n    reset_tokens[recovery_token] = {'email': user_email, 'timestamp': time.time()}\n    send_recovery_email(user_email, recovery_token)\n    return jsonify({'status': 'recovery_initiated'})\ndef send_recovery_email(email, token):\n    print(f'Recovery email sent to {email}')"}