{"title":"Unsafe YAML Deserialization via yaml.load() with FullLoader Bypass","language":"Python","severity":"Critical","cwe":"CWE-502","source_lines":[8],"flow_lines":[8,10],"sink_lines":[10],"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    try:\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        return jsonify({'status': 'provisioned', 'device_id': device_id, 'firmware': firmware_ver})\n    except yaml.YAMLError as e:\n        return jsonify({'error': 'Invalid device manifest'}), 400","explanation":"The endpoint accepts untrusted YAML data from request.data and deserializes it using yaml.load() with FullLoader. While FullLoader is safer than the deprecated unsafe Loader, it still allows instantiation of arbitrary Python objects through YAML tags like !!python/object/apply:, enabling remote code execution through crafted YAML payloads.","remediation":"The fix replaces yaml.load() with yaml.safe_load(), which uses the SafeLoader that only allows basic YAML types (strings, numbers, lists, dicts) and rejects all Python-specific YAML tags that could lead to arbitrary object instantiation or code execution. An additional type check ensures the parsed result is a dictionary before accessing its keys.","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    try:\n        device_config = yaml.safe_load(device_manifest)\n        if not isinstance(device_config, dict):\n            return jsonify({'error': 'Invalid device 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        return jsonify({'status': 'provisioned', 'device_id': device_id, 'firmware': firmware_ver})\n    except yaml.YAMLError as e:\n        return jsonify({'error': 'Invalid device manifest'}), 400"}