{"title":"XXE via lxml.etree.fromstring with resolve_entities=True","language":"Python","severity":"Critical","cwe":"CWE-611","source_lines":[4],"flow_lines":[4,7],"sink_lines":[7],"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(resolve_entities=True, no_network=False)\n    telemetry_doc = etree.fromstring(xml_payload.encode(), parser)\n    device_id = telemetry_doc.find('.//deviceId').text\n    sensor_data = telemetry_doc.find('.//sensorReadings').text\n    metadata = {'device': device_id, 'readings': sensor_data}\n    s3_client.put_object(Bucket='iot-telemetry-bucket', Key=f'data/{device_id}.json', Body=str(metadata))\n    return {'status': 'processed', 'device': device_id}","explanation":"The function accepts untrusted XML input (xml_payload) and parses it using lxml.etree with resolve_entities=True and no_network=False. This configuration allows XML External Entity (XXE) attacks where attackers can read local files, perform SSRF attacks, or cause denial of service through entity expansion.","remediation":"The fix secures the XML parser by setting resolve_entities=False to prevent entity expansion, no_network=True to block external network requests, and dtd_validation=False with load_dtd=False to prevent DTD processing entirely. These settings ensure that malicious XML payloads containing external entity declarations cannot be used to read local files, perform SSRF attacks, or cause denial of service.","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(resolve_entities=False, no_network=True, dtd_validation=False, load_dtd=False)\n    telemetry_doc = etree.fromstring(xml_payload.encode(), parser)\n    device_id = telemetry_doc.find('.//deviceId').text\n    sensor_data = telemetry_doc.find('.//sensorReadings').text\n    metadata = {'device': device_id, 'readings': sensor_data}\n    s3_client.put_object(Bucket='iot-telemetry-bucket', Key=f'data/{device_id}.json', Body=str(metadata))\n    return {'status': 'processed', 'device': device_id}"}