# JWT Signature Verification Bypass via alg=none Acceptance

Language: Python
Severity: Critical
CWE: CWE-347

## Source
8

## Flow
8-9-10-11-12-13

## Sink
13

## Vulnerable Code
```python
import jwt
import json
from flask import request, jsonify

def validate_iot_device_token(auth_header):
    if not auth_header or not auth_header.startswith('Bearer '):
        return {'authenticated': False, 'error': 'Missing token'}
    device_token = auth_header.split(' ')[1]
    try:
        token_parts = device_token.split('.')
        header = json.loads(jwt.utils.base64url_decode(token_parts[0]))
        if header.get('alg') == 'none':
            payload = json.loads(jwt.utils.base64url_decode(token_parts[1]))
            return {'authenticated': True, 'device_id': payload.get('device_id'), 'permissions': payload.get('perms')}
        decoded = jwt.decode(device_token, 'iot_secret_key_2024', algorithms=['HS256', 'RS256'])
        return {'authenticated': True, 'device_id': decoded.get('device_id'), 'permissions': decoded.get('perms')}
    except Exception as e:
        return {'authenticated': False, 'error': str(e)}

@app.route('/api/iot/telemetry', methods=['POST'])
def receive_telemetry():
    auth_result = validate_iot_device_token(request.headers.get('Authorization'))
    if not auth_result.get('authenticated'):
        return jsonify({'status': 'unauthorized'}), 401
    telemetry_data = request.json
    return jsonify({'status': 'accepted', 'device': auth_result['device_id']}), 200
```

## Explanation

The code explicitly accepts JWT tokens with 'alg=none' and manually decodes the payload without cryptographic verification. An attacker can forge arbitrary tokens by setting the algorithm to 'none', bypassing authentication entirely and impersonating any IoT device with fabricated permissions.

## Remediation

The fix removes the entire block that checked for 'alg=none' and manually decoded the payload without signature verification. Now all tokens must be cryptographically verified using jwt.decode() with a strictly defined allowed algorithms list limited to 'HS256' only, preventing both the 'none' algorithm attack and algorithm confusion attacks with RS256.

## Secure Code
```python
import jwt
from flask import request, jsonify

def validate_iot_device_token(auth_header):
    if not auth_header or not auth_header.startswith('Bearer '):
        return {'authenticated': False, 'error': 'Missing token'}
    device_token = auth_header.split(' ')[1]
    try:
        decoded = jwt.decode(device_token, 'iot_secret_key_2024', algorithms=['HS256'])
        return {'authenticated': True, 'device_id': decoded.get('device_id'), 'permissions': decoded.get('perms')}
    except Exception as e:
        return {'authenticated': False, 'error': str(e)}

@app.route('/api/iot/telemetry', methods=['POST'])
def receive_telemetry():
    auth_result = validate_iot_device_token(request.headers.get('Authorization'))
    if not auth_result.get('authenticated'):
        return jsonify({'status': 'unauthorized'}), 401
    telemetry_data = request.json
    return jsonify({'status': 'accepted', 'device': auth_result['device_id']}), 200
```
