{"title":"JWT Signature Verification Bypass via PyJWT decode Without Algorithms Restriction","language":"Python","severity":"Critical","cwe":"CWE-347","source_lines":[9],"flow_lines":[9,11],"sink_lines":[11],"vulnerable_code":"import jwt\nfrom flask import request, jsonify\n\ndef validate_iot_device_token():\n    device_token = request.headers.get('X-Device-Auth')\n    if not device_token:\n        return jsonify({'error': 'Missing device token'}), 401\n    try:\n        payload = jwt.decode(device_token, 'iot_secret_key_2024', options={'verify_signature': True})\n        device_id = payload.get('device_id')\n        permissions = payload.get('permissions', [])\n        return jsonify({'device_id': device_id, 'access_granted': True, 'permissions': permissions})\n    except jwt.InvalidTokenError:\n        return jsonify({'error': 'Invalid token'}), 403","explanation":"The jwt.decode() function is called without specifying the 'algorithms' parameter. In PyJWT 1.x, this allows an attacker to bypass signature verification by crafting tokens using the 'none' algorithm in the JWT header, as PyJWT would accept such tokens even with 'verify_signature': True set. The missing algorithm whitelist means the library does not restrict which signing algorithms are considered valid, enabling complete authentication bypass. Note: In PyJWT >=2.0, omitting the 'algorithms' parameter raises a DecodeError rather than silently accepting 'none' algorithm tokens; this vulnerability is exploitable in environments running PyJWT 1.x.","remediation":"The fix explicitly specifies the 'algorithms' parameter as ['HS256'] in the jwt.decode() call, which restricts token validation to only accept HMAC-SHA256 signed tokens. This prevents attackers from crafting tokens with the 'none' algorithm or other unexpected algorithms to bypass signature verification. This best practice is required in PyJWT >=2.0 and strongly recommended for all versions.","secure_code":"import jwt\nfrom flask import request, jsonify\n\ndef validate_iot_device_token():\n    device_token = request.headers.get('X-Device-Auth')\n    if not device_token:\n        return jsonify({'error': 'Missing device token'}), 401\n    try:\n        payload = jwt.decode(device_token, 'iot_secret_key_2024', algorithms=['HS256'], options={'verify_signature': True})\n        device_id = payload.get('device_id')\n        permissions = payload.get('permissions', [])\n        return jsonify({'device_id': device_id, 'access_granted': True, 'permissions': permissions})\n    except jwt.InvalidTokenError:\n        return jsonify({'error': 'Invalid token'}), 403"}