{"title":"JWT 'none' Algorithm Acceptance via Disabled Signature Verification","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_auth_header = request.headers.get('X-Device-Authorization')\n    if not device_auth_header:\n        return jsonify({'error': 'Missing device token'}), 401\n    try:\n        token_payload = jwt.decode(device_auth_header, options={'verify_signature': False}, algorithms=['HS256', 'RS256', 'none'])\n        device_id = token_payload.get('device_id')\n        firmware_access = token_payload.get('firmware_update_allowed')\n        if device_id:\n            return jsonify({'status': 'authenticated', 'device': device_id, 'firmware_access': firmware_access}), 200\n    except jwt.DecodeError:\n        return jsonify({'error': 'Invalid token format'}), 403\n    return jsonify({'error': 'Authentication failed'}), 401","explanation":"The JWT token from the untrusted HTTP header is decoded with signature verification explicitly disabled ('verify_signature': False) and the 'none' algorithm is explicitly allowed in the algorithms list. This allows attackers to forge arbitrary tokens by setting the algorithm to 'none' and removing the signature entirely, bypassing authentication completely.","remediation":"The fix enables signature verification by removing the 'verify_signature': False option, removes the dangerous 'none' algorithm from the allowed algorithms list (restricting to only 'HS256'), and provides a proper secret key for signature validation loaded from an environment variable. Additional exception handling for invalid signatures and expired tokens improves error reporting. The missing 'import os' statement has also been added to ensure the fix is syntactically complete.","secure_code":"import os\nimport jwt\nfrom flask import request, jsonify\n\nDEVICE_SECRET_KEY = os.environ.get('DEVICE_JWT_SECRET_KEY')\n\ndef validate_iot_device_token():\n    device_auth_header = request.headers.get('X-Device-Authorization')\n    if not device_auth_header:\n        return jsonify({'error': 'Missing device token'}), 401\n    try:\n        token_payload = jwt.decode(device_auth_header, key=DEVICE_SECRET_KEY, algorithms=['HS256'])\n        device_id = token_payload.get('device_id')\n        firmware_access = token_payload.get('firmware_update_allowed')\n        if device_id:\n            return jsonify({'status': 'authenticated', 'device': device_id, 'firmware_access': firmware_access}), 200\n    except jwt.InvalidSignatureError:\n        return jsonify({'error': 'Invalid token signature'}), 403\n    except jwt.DecodeError:\n        return jsonify({'error': 'Invalid token format'}), 403\n    except jwt.ExpiredSignatureError:\n        return jsonify({'error': 'Token expired'}), 401\n    return jsonify({'error': 'Authentication failed'}), 401"}