{"title":"Unsafe YAML Deserialization via yaml.load() with FullLoader","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    device_config = yaml.load(device_manifest, Loader=yaml.FullLoader)\n    device_id = device_config.get('device_id', 'unknown')\n    firmware_ver = device_config.get('firmware_version', '1.0.0')\n    capabilities = device_config.get('capabilities', [])\n    register_device_to_cloud(device_id, firmware_ver, capabilities)\n    return jsonify({'status': 'provisioned', 'device_id': device_id})\n\ndef register_device_to_cloud(dev_id, fw_ver, caps):\n    pass","explanation":"The application accepts untrusted YAML data from HTTP POST requests and deserializes it using yaml.load() with FullLoader. This allows attackers to execute arbitrary Python code through YAML's ability to instantiate arbitrary Python objects, leading to Remote Code Execution (RCE).","remediation":"The fix replaces yaml.load() with yaml.safe_load(), which only deserializes standard YAML tags (strings, numbers, lists, dicts) and refuses to instantiate arbitrary Python objects. Additionally, a type check ensures the deserialized result is a dictionary before accessing its fields, preventing unexpected behavior from malformed input.","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    device_config = yaml.safe_load(device_manifest)\n    if not isinstance(device_config, dict):\n        return jsonify({'status': 'error', 'message': 'Invalid manifest format'}), 400\n    device_id = device_config.get('device_id', 'unknown')\n    firmware_ver = device_config.get('firmware_version', '1.0.0')\n    capabilities = device_config.get('capabilities', [])\n    register_device_to_cloud(device_id, firmware_ver, capabilities)\n    return jsonify({'status': 'provisioned', 'device_id': device_id})\n\ndef register_device_to_cloud(dev_id, fw_ver, caps):\n    pass"}