# JWT Algorithm Confusion via alg=none Acceptance

Language: Python
Severity: Critical
CWE: CWE-347

## Source
9

## Flow
9-10

## Sink
10

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

def verify_iot_device_token(auth_header):
    device_token = auth_header.replace('Bearer ', '')
    token_parts = device_token.split('.')
    header_data = json.loads(jwt.utils.base64url_decode(token_parts[0]))
    allowed_algos = ['HS256', 'RS256', header_data.get('alg')]
    decoded = jwt.decode(device_token, options={'verify_signature': False}, algorithms=allowed_algos)
    if decoded.get('device_id') and decoded.get('permissions'):
        return {'status': 'authenticated', 'device': decoded['device_id'], 'access': decoded['permissions']}
    return {'status': 'denied'}
```

## Explanation

The code extracts the 'alg' header from an unverified JWT token and adds it to the allowed algorithms list, then decodes the token with signature verification disabled. This allows attackers to create tokens with 'alg=none', bypassing all cryptographic validation and forging arbitrary device_id and permissions claims.

## Remediation

The fix removes the dynamic algorithm list that trusted the token's own 'alg' header claim and enforces a strict, server-side allowlist of only 'HS256'. Signature verification is now enabled (the default behavior) by removing the 'options={"verify_signature": False}' parameter, ensuring all tokens are cryptographically validated against a known secret key before being accepted.

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

SECRET_KEY = None  # Must be configured with actual secret key at startup

def verify_iot_device_token(auth_header):
    device_token = auth_header.replace('Bearer ', '')
    decoded = jwt.decode(device_token, SECRET_KEY, algorithms=['HS256'])
    if decoded.get('device_id') and decoded.get('permissions'):
        return {'status': 'authenticated', 'device': decoded['device_id'], 'access': decoded['permissions']}
    return {'status': 'denied'}
```
