{"title":"XML External Entity (XXE) Injection","language":"Python","severity":"Critical","cwe":"CWE-611","source_lines":[6],"flow_lines":[6,7,8],"sink_lines":[8],"vulnerable_code":"from lxml import etree\nfrom flask import Flask, request, jsonify\napp = Flask(__name__)\n@app.route('/iot/device/config', methods=['POST'])\ndef parse_device_telemetry():\n    raw_payload = request.data\n    xml_parser = etree.XMLParser(resolve_entities=True, no_network=False)\n    try:\n        device_tree = etree.fromstring(raw_payload, xml_parser)\n        sensor_vals = {node.tag: node.text for node in device_tree.iter()}\n        cfg_blob = device_tree.find('.//config')\n        result_map = {'status': 'ok', 'cfg': cfg_blob.text if cfg_blob is not None else None, 'sensors': sensor_vals}\n        return jsonify(result_map)\n    except etree.XMLSyntaxError as parse_err:\n        return jsonify({'error': str(parse_err)}), 400","explanation":"The raw HTTP request body (line 6) is passed directly to etree.fromstring() (line 8) using an XMLParser configured with resolve_entities=True and no_network=False (line 7). This allows an attacker to embed external entity declarations (XXE) in the XML payload, enabling local file disclosure (e.g., /etc/passwd) or Server-Side Request Forgery (SSRF) to internal metadata endpoints.","remediation":"The fix secures the XMLParser by setting resolve_entities=False (preventing expansion of external and internal entity references), no_network=True (blocking any network-based entity resolution), dtd_validation=False, and load_dtd=False (preventing DTD loading entirely). Together, these settings eliminate the XXE attack surface by ensuring no external entities can be resolved from the filesystem or network.","secure_code":"from lxml import etree\nfrom flask import Flask, request, jsonify\napp = Flask(__name__)\n@app.route('/iot/device/config', methods=['POST'])\ndef parse_device_telemetry():\n    raw_payload = request.data\n    xml_parser = etree.XMLParser(resolve_entities=False, no_network=True, dtd_validation=False, load_dtd=False)\n    try:\n        device_tree = etree.fromstring(raw_payload, xml_parser)\n        sensor_vals = {node.tag: node.text for node in device_tree.iter()}\n        cfg_blob = device_tree.find('.//config')\n        result_map = {'status': 'ok', 'cfg': cfg_blob.text if cfg_blob is not None else None, 'sensors': sensor_vals}\n        return jsonify(result_map)\n    except etree.XMLSyntaxError as parse_err:\n        return jsonify({'error': str(parse_err)}), 400"}