# JWT Authentication Bypass via alg=none Acceptance

Language: Python
Severity: Critical
CWE: CWE-347

## Source
9

## Flow
9-10-11

## Sink
11

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

def validate_iot_device_token():
    auth_header = request.headers.get('X-Device-Auth')
    if not auth_header:
        return jsonify({'error': 'No token'}), 401
    try:
        device_token = auth_header.split(' ')[1]
        payload = jwt.decode(device_token, options={"verify_signature": False})
        device_id = payload.get('device_id')
        if device_id:
            return jsonify({'status': 'authorized', 'device': device_id, 'admin': payload.get('is_admin', False)})
    except Exception as e:
        return jsonify({'error': 'Invalid token'}), 403
    return jsonify({'error': 'Unauthorized'}), 401
```

## Explanation

The code disables JWT signature verification by setting 'verify_signature: False', allowing attackers to forge arbitrary JWT tokens without knowing the secret key. An attacker can craft tokens with elevated privileges (is_admin: true) or impersonate any device_id, completely bypassing authentication.

## Remediation

The fix enforces JWT signature verification by providing a secret key and explicitly setting verify_signature to True. It restricts the allowed algorithms to only HS256, preventing 'none' algorithm attacks. Additionally, it removes trust in the 'is_admin' claim from the token payload to prevent privilege escalation, and requires essential claims like 'device_id' and 'exp' to be present.

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

DEVICE_SECRET_KEY = os.environ.get('DEVICE_JWT_SECRET_KEY')
ALLOWED_ALGORITHMS = ['HS256']

def validate_iot_device_token():
    auth_header = request.headers.get('X-Device-Auth')
    if not auth_header:
        return jsonify({'error': 'No token'}), 401
    try:
        device_token = auth_header.split(' ')[1]
        payload = jwt.decode(
            device_token,
            key=DEVICE_SECRET_KEY,
            algorithms=ALLOWED_ALGORITHMS,
            options={"verify_signature": True, "require": ["device_id", "exp"]}
        )
        device_id = payload.get('device_id')
        if device_id:
            return jsonify({'status': 'authorized', 'device': device_id})
    except jwt.ExpiredSignatureError:
        return jsonify({'error': 'Token expired'}), 401
    except jwt.InvalidAlgorithmError:
        return jsonify({'error': 'Invalid token algorithm'}), 403
    except jwt.InvalidTokenError as e:
        return jsonify({'error': 'Invalid token'}), 403
    except Exception as e:
        return jsonify({'error': 'Invalid token'}), 403
    return jsonify({'error': 'Unauthorized'}), 401
```
