{"title":"Unsafe YAML Deserialization via yaml.load() with Loader","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_manifest = request.data.decode('utf-8')\n    parsed_config = yaml.load(device_manifest, Loader=yaml.Loader)\n    device_id = parsed_config.get('device_id', 'unknown')\n    firmware_ver = parsed_config.get('firmware_version', '1.0.0')\n    security_profile = parsed_config.get('security_profile', {})\n    print(f\"Provisioning device {device_id} with firmware {firmware_ver}\")\n    return jsonify({\"status\": \"provisioned\", \"device_id\": device_id, \"profile\": security_profile})","explanation":"The application uses yaml.load() with yaml.Loader to deserialize untrusted YAML data from user requests without validation. This allows attackers to execute arbitrary Python code through malicious YAML payloads containing Python object constructor tags, leading to Remote Code Execution (RCE).","remediation":"The fix replaces yaml.load() with yaml.Loader with yaml.safe_load(), which only deserializes standard YAML types (strings, numbers, lists, dicts) and refuses to construct arbitrary Python objects. Additionally, a type check ensures the parsed result is a dictionary before accessing fields, preventing unexpected behavior from non-mapping YAML inputs.","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_manifest = request.data.decode('utf-8')\n    parsed_config = yaml.safe_load(device_manifest)\n    if not isinstance(parsed_config, dict):\n        return jsonify({\"error\": \"Invalid manifest format\"}), 400\n    device_id = parsed_config.get('device_id', 'unknown')\n    firmware_ver = parsed_config.get('firmware_version', '1.0.0')\n    security_profile = parsed_config.get('security_profile', {})\n    print(f\"Provisioning device {device_id} with firmware {firmware_ver}\")\n    return jsonify({\"status\": \"provisioned\", \"device_id\": device_id, \"profile\": security_profile})"}