# JWT 'none' Algorithm Acceptance via Disabled Signature Verification

Language: Python
Severity: Critical
CWE: CWE-347

## Source
9

## Flow
9-11

## Sink
11

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

def validate_iot_device_token():
    device_auth_header = request.headers.get('X-Device-Authorization')
    if not device_auth_header:
        return jsonify({'error': 'Missing device token'}), 401
    try:
        token_payload = jwt.decode(device_auth_header, options={'verify_signature': False}, algorithms=['HS256', 'RS256', 'none'])
        device_id = token_payload.get('device_id')
        firmware_access = token_payload.get('firmware_update_allowed')
        if device_id:
            return jsonify({'status': 'authenticated', 'device': device_id, 'firmware_access': firmware_access}), 200
    except jwt.DecodeError:
        return jsonify({'error': 'Invalid token format'}), 403
    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
```python
import os
import jwt
from flask import request, jsonify

DEVICE_SECRET_KEY = os.environ.get('DEVICE_JWT_SECRET_KEY')

def validate_iot_device_token():
    device_auth_header = request.headers.get('X-Device-Authorization')
    if not device_auth_header:
        return jsonify({'error': 'Missing device token'}), 401
    try:
        token_payload = jwt.decode(device_auth_header, key=DEVICE_SECRET_KEY, algorithms=['HS256'])
        device_id = token_payload.get('device_id')
        firmware_access = token_payload.get('firmware_update_allowed')
        if device_id:
            return jsonify({'status': 'authenticated', 'device': device_id, 'firmware_access': firmware_access}), 200
    except jwt.InvalidSignatureError:
        return jsonify({'error': 'Invalid token signature'}), 403
    except jwt.DecodeError:
        return jsonify({'error': 'Invalid token format'}), 403
    except jwt.ExpiredSignatureError:
        return jsonify({'error': 'Token expired'}), 401
    return jsonify({'error': 'Authentication failed'}), 401
```
