{"title":"Billion Laughs XML Entity Expansion Denial of Service","language":"Python","severity":"High","cwe":"CWE-776","source_lines":[7],"flow_lines":[7,8,9],"sink_lines":[9],"vulnerable_code":"import xml.etree.ElementTree as ET\nfrom flask import Flask, request, jsonify\n\napp = Flask(__name__)\n\n@app.route('/iot/device/config', methods=['POST'])\ndef update_device_configuration():\n    device_xml = request.data.decode('utf-8')\n    parser = ET.XMLParser()\n    config_tree = ET.fromstring(device_xml, parser=parser)\n    device_id = config_tree.find('device_id').text\n    settings = {child.tag: child.text for child in config_tree.find('settings')}\n    return jsonify({'status': 'configured', 'device': device_id, 'applied_settings': settings})","explanation":"The code uses xml.etree.ElementTree to parse untrusted XML data from the POST request without disabling entity expansion. This allows an attacker to craft malicious XML with nested entity definitions that exponentially expand during parsing, consuming excessive memory and CPU resources, leading to a Denial of Service (Billion Laughs attack).","remediation":"The fix replaces the standard xml.etree.ElementTree module with defusedxml.ElementTree, which automatically prevents entity expansion attacks (Billion Laughs), external entity processing (XXE), and other XML-based attacks. Additionally, error handling and input validation were added to gracefully handle malformed XML and missing elements.","secure_code":"import defusedxml.ElementTree as ET\nfrom flask import Flask, request, jsonify\n\napp = Flask(__name__)\n\n@app.route('/iot/device/config', methods=['POST'])\ndef update_device_configuration():\n    device_xml = request.data.decode('utf-8')\n    try:\n        config_tree = ET.fromstring(device_xml)\n    except ET.ParseError:\n        return jsonify({'status': 'error', 'message': 'Invalid XML payload'}), 400\n    device_id_elem = config_tree.find('device_id')\n    settings_elem = config_tree.find('settings')\n    if device_id_elem is None or settings_elem is None:\n        return jsonify({'status': 'error', 'message': 'Missing required XML elements'}), 400\n    device_id = device_id_elem.text\n    settings = {child.tag: child.text for child in settings_elem}\n    return jsonify({'status': 'configured', 'device': device_id, 'applied_settings': settings})"}