{"title":"YAML Deserialization Remote Code Execution","language":"Python","severity":"Critical","cwe":"CWE-502","source_lines":[6],"flow_lines":[6,7],"sink_lines":[7],"vulnerable_code":"from flask import Flask, request\nimport yaml\napp = Flask(__name__)\n@app.route('/iot/device/config', methods=['POST'])\ndef sync_device_profile():\n    raw_cfg = request.data.decode('utf-8')\n    dev_profile = yaml.load(raw_cfg)\n    dev_id = dev_profile.get('device_id', 'unknown')\n    fw_ver = dev_profile.get('firmware', '0.0.0')\n    return {\"status\": \"synced\", \"id\": dev_id, \"fw\": fw_ver}, 200","explanation":"The raw HTTP request body is decoded and passed directly to yaml.load() without specifying a safe Loader. PyYAML's yaml.load() without a Loader argument (or with the default FullLoader/UnsafeLoader in older versions) allows deserialization of arbitrary Python objects via YAML tags like !!python/object/apply:os.system, enabling remote code execution on the server.","remediation":"The fix replaces `yaml.load(raw_cfg)` with `yaml.safe_load(raw_cfg)`, which only deserializes standard YAML types (strings, numbers, lists, dicts) and refuses to construct arbitrary Python objects from tags like `!!python/object/apply`. An additional type check ensures the parsed result is a dictionary before accessing keys, preventing unexpected behavior from non-mapping YAML inputs.","secure_code":"from flask import Flask, request\nimport yaml\napp = Flask(__name__)\n@app.route('/iot/device/config', methods=['POST'])\ndef sync_device_profile():\n    raw_cfg = request.data.decode('utf-8')\n    dev_profile = yaml.safe_load(raw_cfg)\n    if not isinstance(dev_profile, dict):\n        return {\"status\": \"error\", \"message\": \"Invalid configuration format\"}, 400\n    dev_id = dev_profile.get('device_id', 'unknown')\n    fw_ver = dev_profile.get('firmware', '0.0.0')\n    return {\"status\": \"synced\", \"id\": dev_id, \"fw\": fw_ver}, 200"}