{"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/configure', methods=['POST'])\ndef apply_device_config():\n    device_yaml = request.data.decode('utf-8')\n    parsed_config = yaml.load(device_yaml, Loader=yaml.FullLoader)\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': 'configured', 'device': device_id, 'firmware': firmware_ver, 'interval': telemetry_interval})","explanation":"The application accepts untrusted YAML input from request.data and deserializes it using yaml.load() with FullLoader, which can instantiate arbitrary Python objects. An attacker can craft malicious YAML payloads containing Python object serialization directives to execute arbitrary code on the server.","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 parsed result is a dictionary before accessing keys, preventing unexpected input types from causing errors.","secure_code":"import yaml\nfrom flask import Flask, request, jsonify\n\napp = Flask(__name__)\n\n@app.route('/iot/device/configure', methods=['POST'])\ndef apply_device_config():\n    device_yaml = request.data.decode('utf-8')\n    parsed_config = yaml.safe_load(device_yaml)\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': 'configured', 'device': device_id, 'firmware': firmware_ver, 'interval': telemetry_interval})"}