{"title":"JWT Algorithm Confusion via Unverified `alg` Header","language":"Python","severity":"Critical","cwe":"CWE-347","source_lines":[5],"flow_lines":[5,10],"sink_lines":[10],"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        with open('/etc/iot/device_public.pem', 'r') as key_file:\n            verification_key = key_file.read()\n        payload = jwt.decode(device_token, verification_key, algorithms=['RS256', 'HS256', 'none'])\n        device_id = payload.get('device_id')\n        return jsonify({'status': 'authorized', 'device_id': device_id, 'permissions': payload.get('perms')}), 200\n    except jwt.InvalidTokenError:\n        return jsonify({'error': 'Invalid device credentials'}), 403","explanation":"The code accepts an untrusted JWT token from the X-Device-Auth header and decodes it using jwt.decode() with multiple algorithms including 'HS256' and 'none'. This allows an attacker to exploit algorithm confusion by changing the 'alg' header to 'HS256' and signing the token with the public key (which is treated as an HMAC secret), or by setting 'alg' to 'none' to bypass signature verification entirely.","remediation":"The fix restricts the allowed algorithms to only 'RS256', which is the expected asymmetric algorithm for verifying tokens signed with the corresponding private key. This prevents algorithm confusion attacks where an attacker could switch to 'HS256' (using the public key as an HMAC secret) or 'none' (bypassing signature verification entirely).","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        with open('/etc/iot/device_public.pem', 'r') as key_file:\n            verification_key = key_file.read()\n        payload = jwt.decode(device_token, verification_key, algorithms=['RS256'])\n        device_id = payload.get('device_id')\n        return jsonify({'status': 'authorized', 'device_id': device_id, 'permissions': payload.get('perms')}), 200\n    except jwt.InvalidTokenError:\n        return jsonify({'error': 'Invalid device credentials'}), 403"}