{"title":"XXE via lxml.etree.fromstring External Entity Resolution","language":"Python","severity":"High","cwe":"CWE-611","source_lines":[6],"flow_lines":[6,6],"sink_lines":[6],"vulnerable_code":"from lxml import etree\nimport boto3\n\ndef process_iot_device_config(device_xml_payload):\n    s3_client = boto3.client('s3')\n    parsed_config = etree.fromstring(device_xml_payload)\n    device_id = parsed_config.find('.//deviceId').text\n    firmware_ver = parsed_config.find('.//firmware').text\n    config_data = etree.tostring(parsed_config, encoding='unicode')\n    s3_client.put_object(Bucket='iot-device-configs', Key=f'{device_id}.xml', Body=config_data)\n    return {'status': 'configured', 'device': device_id, 'version': firmware_ver}","explanation":"The code uses lxml.etree.fromstring() to parse untrusted XML from IoT devices without disabling external entity resolution. An attacker can inject malicious XML with external entity declarations to read arbitrary files from the server, perform SSRF attacks, or cause denial of service through entity expansion attacks.","remediation":"The fix creates a secure XMLParser instance with resolve_entities=False, no_network=True, dtd_validation=False, and load_dtd=False, which prevents external entity resolution, network access during parsing, and DTD loading. This parser is then passed to etree.fromstring() to ensure all XML parsing is performed securely against XXE attacks.","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(resolve_entities=False, no_network=True, dtd_validation=False, load_dtd=False)\n    parsed_config = etree.fromstring(device_xml_payload, parser=parser)\n    device_id = parsed_config.find('.//deviceId').text\n    firmware_ver = parsed_config.find('.//firmware').text\n    config_data = etree.tostring(parsed_config, encoding='unicode')\n    s3_client.put_object(Bucket='iot-device-configs', Key=f'{device_id}.xml', Body=config_data)\n    return {'status': 'configured', 'device': device_id, 'version': firmware_ver}"}