# JWT Algorithm Confusion via Public-Key-as-HMAC-Secret Misuse

Language: Python
Severity: Critical
CWE: CWE-347

## Source
3

## Flow
3-7

## Sink
7

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

def verify_iot_device_token(device_jwt):
    with open('/etc/iot/device_public.pem', 'r') as key_file:
        rsa_public_key = key_file.read()
    try:
        device_data = jwt.decode(device_jwt, rsa_public_key, algorithms=['RS256', 'HS256'])
        device_id = device_data.get('device_id')
        if device_id:
            return {'status': 'authorized', 'device_id': device_id, 'permissions': device_data.get('permissions', [])}
    except jwt.InvalidTokenError:
        return {'status': 'unauthorized'}
    return {'status': 'error'}
```

## Explanation

The JWT verification allows both RS256 (asymmetric) and HS256 (symmetric) algorithms. An attacker can create a malicious JWT signed with HS256 using the public RSA key as the HMAC secret. Since the public key is known, attackers can forge valid tokens with arbitrary claims including elevated permissions.

## Remediation

The fix restricts the allowed algorithms list to only 'RS256', removing 'HS256' from the accepted algorithms. This prevents the algorithm confusion attack where an attacker could sign a forged token using HS256 with the publicly available RSA public key as the HMAC secret, since the decoder will now reject any token that isn't signed with RS256.

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

def verify_iot_device_token(device_jwt):
    with open('/etc/iot/device_public.pem', 'r') as key_file:
        rsa_public_key = key_file.read()
    try:
        device_data = jwt.decode(device_jwt, rsa_public_key, algorithms=['RS256'])
        device_id = device_data.get('device_id')
        if device_id:
            return {'status': 'authorized', 'device_id': device_id, 'permissions': device_data.get('permissions', [])}
    except jwt.InvalidTokenError:
        return {'status': 'unauthorized'}
    return {'status': 'error'}
```
