{"title":"YAML Deserialization via yaml.load with UnsafeLoader","language":"Python","severity":"Critical","cwe":"CWE-502","source_lines":[8],"flow_lines":[8,9],"sink_lines":[9],"vulnerable_code":"import yaml\nfrom flask import Flask, request, jsonify\n\napp = Flask(__name__)\n\n@app.route('/iot/device/provision', methods=['POST'])\ndef provision_iot_device():\n    device_config = request.data.decode('utf-8')\n    parsed_config = yaml.load(device_config, Loader=yaml.UnsafeLoader)\n    device_id = parsed_config.get('device_id', 'unknown')\n    firmware_ver = parsed_config.get('firmware_version', '1.0.0')\n    telemetry_interval = parsed_config.get('telemetry_interval', 60)\n    return jsonify({'status': 'provisioned', 'device': device_id, 'firmware': firmware_ver, 'interval': telemetry_interval})","explanation":"The application uses yaml.load() with UnsafeLoader to deserialize untrusted YAML data from an HTTP POST request. UnsafeLoader allows arbitrary Python object instantiation, enabling attackers to execute malicious code by crafting specially-formed YAML payloads that instantiate dangerous Python objects during deserialization.","remediation":"The fix replaces yaml.load() with yaml.UnsafeLoader with yaml.safe_load(), which only deserializes standard YAML tags (strings, numbers, lists, dicts) and prevents instantiation of arbitrary Python objects. An additional type check ensures the parsed result is a dictionary before accessing keys, providing defense against unexpected input formats.","secure_code":"import yaml\nfrom flask import Flask, request, jsonify\n\napp = Flask(__name__)\n\n@app.route('/iot/device/provision', methods=['POST'])\ndef provision_iot_device():\n    device_config = request.data.decode('utf-8')\n    parsed_config = yaml.safe_load(device_config)\n    if not isinstance(parsed_config, dict):\n        return jsonify({'status': 'error', 'message': 'Invalid configuration format'}), 400\n    device_id = parsed_config.get('device_id', 'unknown')\n    firmware_ver = parsed_config.get('firmware_version', '1.0.0')\n    telemetry_interval = parsed_config.get('telemetry_interval', 60)\n    return jsonify({'status': 'provisioned', 'device': device_id, 'firmware': firmware_ver, 'interval': telemetry_interval})"}