{"title":"XML External Entity (XXE) via lxml.etree.fromstring with DTD Enabled","language":"Python","severity":"High","cwe":"CWE-611","source_lines":[1],"flow_lines":[1,3,4],"sink_lines":[4],"vulnerable_code":"from lxml import etree\nimport boto3\n\ndef process_iot_device_telemetry(xml_payload):\n    s3_client = boto3.client('s3')\n    parser = etree.XMLParser(dtd_validation=True, load_dtd=True, resolve_entities=True)\n    telemetry_doc = etree.fromstring(xml_payload.encode(), parser)\n    device_id = telemetry_doc.find('.//deviceId').text\n    sensor_data = telemetry_doc.find('.//readings').text\n    s3_client.put_object(Bucket='iot-telemetry-lake', Key=f'devices/{device_id}/data.xml', Body=sensor_data)\n    return {'status': 'uploaded', 'device': device_id, 'data_size': len(sensor_data)}","explanation":"The code creates an XML parser with DTD validation, DTD loading, and entity resolution all enabled (line 6), then parses untrusted XML input from IoT devices using etree.fromstring() (line 7). This allows attackers to inject malicious XML with external entity references that can read local files, perform SSRF attacks, or cause denial of service through entity expansion attacks.","remediation":"The fix disables DTD validation, DTD loading, and entity resolution in the XML parser, and additionally sets no_network=True to prevent any network access during parsing. This prevents attackers from injecting external entity references that could read local files, perform SSRF attacks, or cause denial of service through entity expansion.","secure_code":"from lxml import etree\nimport boto3\n\ndef process_iot_device_telemetry(xml_payload):\n    s3_client = boto3.client('s3')\n    parser = etree.XMLParser(dtd_validation=False, load_dtd=False, resolve_entities=False, no_network=True)\n    telemetry_doc = etree.fromstring(xml_payload.encode(), parser)\n    device_id = telemetry_doc.find('.//deviceId').text\n    sensor_data = telemetry_doc.find('.//readings').text\n    s3_client.put_object(Bucket='iot-telemetry-lake', Key=f'devices/{device_id}/data.xml', Body=sensor_data)\n    return {'status': 'uploaded', 'device': device_id, 'data_size': len(sensor_data)}"}