{"title":"XML External Entity (XXE) via lxml.etree.parse on Untrusted XML","language":"Python","severity":"Critical","cwe":"CWE-611","source_lines":[6],"flow_lines":[6,7],"sink_lines":[7],"vulnerable_code":"from lxml import etree\nimport boto3\n\ndef process_iot_device_config(device_xml_payload):\n    s3_client = boto3.client('s3')\n    parser = etree.XMLParser(resolve_entities=True)\n    config_tree = etree.parse(device_xml_payload, parser)\n    device_id = config_tree.find('.//DeviceID').text\n    firmware_url = config_tree.find('.//FirmwareUpdateURL').text\n    telemetry_interval = config_tree.find('.//TelemetryInterval').text\n    config_data = {'device': device_id, 'firmware': firmware_url, 'interval': telemetry_interval}\n    s3_client.put_object(Bucket='iot-device-configs', Key=f'{device_id}.json', Body=str(config_data))\n    return {'status': 'configured', 'device_id': device_id, 'next_update': firmware_url}","explanation":"The function accepts untrusted XML input from IoT devices and parses it with resolve_entities=True enabled, allowing XML External Entity (XXE) attacks. An attacker can craft malicious XML with external entity declarations to read local files (e.g., AWS credentials from /root/.aws/credentials) or perform SSRF attacks against internal AWS metadata endpoints.","remediation":"The fix disables XML external entity processing by setting resolve_entities=False, no_network=True, dtd_validation=False, and load_dtd=False in the XMLParser configuration. This prevents attackers from injecting malicious entity declarations that could read local files or perform SSRF attacks against internal services like the AWS metadata endpoint.","secure_code":"from lxml import etree\nimport boto3\n\ndef process_iot_device_config(device_xml_payload):\n    s3_client = boto3.client('s3')\n    parser = etree.XMLParser(\n        resolve_entities=False,\n        no_network=True,\n        dtd_validation=False,\n        load_dtd=False\n    )\n    config_tree = etree.parse(device_xml_payload, parser)\n    device_id = config_tree.find('.//DeviceID').text\n    firmware_url = config_tree.find('.//FirmwareUpdateURL').text\n    telemetry_interval = config_tree.find('.//TelemetryInterval').text\n    config_data = {'device': device_id, 'firmware': firmware_url, 'interval': telemetry_interval}\n    s3_client.put_object(Bucket='iot-device-configs', Key=f'{device_id}.json', Body=str(config_data))\n    return {'status': 'configured', 'device_id': device_id, 'next_update': firmware_url}"}