# Unsafe YAML Deserialization via yaml.load

Language: Python
Severity: Critical
CWE: CWE-502

## Source
8

## Flow
8-9

## Sink
9

## Vulnerable Code
```python
import yaml
from flask import Flask, request

app = Flask(__name__)

@app.route('/iot/device/provision', methods=['POST'])
def provision_iot_device():
    device_manifest = request.data.decode('utf-8')
    device_config = yaml.load(device_manifest, Loader=yaml.Loader)
    device_id = device_config.get('device_id')
    firmware_version = device_config.get('firmware')
    print(f"Provisioning device {device_id} with firmware {firmware_version}")
    return {"status": "provisioned", "device": device_id}, 200
```

## Explanation

The code uses yaml.load() with yaml.Loader to deserialize untrusted user input from request.data without validation. This allows arbitrary Python object instantiation, enabling remote code execution through malicious YAML payloads containing Python object constructors.

## Remediation

The fix replaces yaml.load() with yaml.safe_load(), which only deserializes standard YAML tags (strings, numbers, lists, dicts) and does not allow arbitrary Python object instantiation. An additional type check ensures the parsed result is a dictionary, preventing unexpected input formats from causing downstream errors.

## Secure Code
```python
import yaml
from flask import Flask, request

app = Flask(__name__)

@app.route('/iot/device/provision', methods=['POST'])
def provision_iot_device():
    device_manifest = request.data.decode('utf-8')
    device_config = yaml.safe_load(device_manifest)
    if not isinstance(device_config, dict):
        return {"error": "Invalid device manifest format"}, 400
    device_id = device_config.get('device_id')
    firmware_version = device_config.get('firmware')
    print(f"Provisioning device {device_id} with firmware {firmware_version}")
    return {"status": "provisioned", "device": device_id}, 200
```
