# Unsafe YAML Deserialization via yaml.load with FullLoader

Language: Python
Severity: Critical
CWE: CWE-502

## Source
8

## Flow
8-9

## Sink
9

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

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.FullLoader)
    device_id = device_config.get('device_id', 'unknown')
    firmware_version = device_config.get('firmware', '1.0.0')
    security_profile = device_config.get('security_settings', {})
    print(f"Provisioning device {device_id} with firmware {firmware_version}")
    return jsonify({'status': 'provisioned', 'device_id': device_id, 'profile': security_profile})
```

## Explanation

The application accepts untrusted YAML input from request.data and deserializes it using yaml.load() with FullLoader, which can execute arbitrary Python code embedded in the YAML. An attacker can craft a malicious YAML payload containing Python object constructors that execute commands during deserialization.

## Remediation

The fix replaces yaml.load() with yaml.safe_load(), which only deserializes standard YAML tags (strings, numbers, lists, dicts) and refuses to construct arbitrary Python objects. Additionally, a type check ensures the parsed YAML is a dictionary before accessing its keys, preventing unexpected behavior from non-mapping YAML inputs.

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

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 jsonify({'status': 'error', 'message': 'Invalid device manifest format'}), 400
    device_id = device_config.get('device_id', 'unknown')
    firmware_version = device_config.get('firmware', '1.0.0')
    security_profile = device_config.get('security_settings', {})
    print(f"Provisioning device {device_id} with firmware {firmware_version}")
    return jsonify({'status': 'provisioned', 'device_id': device_id, 'profile': security_profile})
```
