{"title":"JWT Verification Bypass via alg=none Acceptance","language":"Python","severity":"Critical","cwe":"CWE-347","source_lines":[6],"flow_lines":[6,8,9,10],"sink_lines":[8],"vulnerable_code":"import jwt\nimport json\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})\n        device_id = token_payload.get('device_id')\n        firmware_access = token_payload.get('firmware_update_permission')\n        if device_id and firmware_access:\n            return jsonify({'status': 'authorized', 'device': device_id, 'firmware_access': firmware_access}), 200\n    except Exception as e:\n        return jsonify({'error': 'Invalid token format'}), 403\n    return jsonify({'error': 'Unauthorized device'}), 401","explanation":"The code disables JWT signature verification by setting 'verify_signature': False, allowing attackers to forge tokens with arbitrary claims. Any attacker can create a JWT with elevated permissions (e.g., firmware_update_permission: true) without possessing the secret key, bypassing authentication entirely.","remediation":"The fix enforces cryptographic signature verification by providing a secret key and explicitly specifying allowed algorithms (only HS256), which prevents both the 'alg=none' bypass and algorithm confusion attacks. Additionally, it requires essential claims including an expiration time ('exp') to prevent token replay, and adds granular error handling for different JWT failure modes.","secure_code":"import jwt\nimport json\nimport os\nfrom flask import request, jsonify\n\nDEVICE_JWT_SECRET = os.environ.get('DEVICE_JWT_SECRET')\nALLOWED_ALGORITHMS = ['HS256']\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    if not DEVICE_JWT_SECRET:\n        return jsonify({'error': 'Server configuration error'}), 500\n    try:\n        token_payload = jwt.decode(\n            device_auth_header,\n            key=DEVICE_JWT_SECRET,\n            algorithms=ALLOWED_ALGORITHMS,\n            options={'verify_signature': True, 'require': ['device_id', 'firmware_update_permission', 'exp']}\n        )\n        device_id = token_payload.get('device_id')\n        firmware_access = token_payload.get('firmware_update_permission')\n        if device_id and firmware_access:\n            return jsonify({'status': 'authorized', 'device': device_id, 'firmware_access': firmware_access}), 200\n    except jwt.ExpiredSignatureError:\n        return jsonify({'error': 'Token expired'}), 401\n    except jwt.InvalidAlgorithmError:\n        return jsonify({'error': 'Invalid token algorithm'}), 403\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 Exception as e:\n        return jsonify({'error': 'Token validation failed'}), 403\n    return jsonify({'error': 'Unauthorized device'}), 401"}