{"title":"XML External Entity (XXE) via lxml.etree.parse()","language":"Python","severity":"High","cwe":"CWE-611","source_lines":[4],"flow_lines":[4,6],"sink_lines":[6],"vulnerable_code":"from lxml import etree\nimport boto3\n\ndef sync_iot_device_config(device_xml_stream, device_id):\n    s3_client = boto3.client('s3')\n    config_tree = etree.parse(device_xml_stream)\n    device_name = config_tree.find('.//device_name').text\n    firmware_ver = config_tree.find('.//firmware').text\n    telemetry_interval = config_tree.find('.//telemetry_interval').text\n    config_data = {'device': device_name, 'firmware': firmware_ver, 'interval': telemetry_interval}\n    s3_client.put_object(Bucket='iot-device-configs', Key=f'{device_id}.json', Body=str(config_data))\n    return {'status': 'synced', 'device': device_name, 'firmware': firmware_ver}","explanation":"The function uses lxml.etree.parse() to parse XML from an untrusted device_xml_stream without disabling external entity resolution. This allows an attacker to inject malicious XML with external entity references that can read local files, perform SSRF attacks, or cause denial of service through billion laughs 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 the parser from resolving external entities, accessing network resources, or loading DTDs. This hardened parser is then passed to etree.parse() to safely parse the XML input without XXE vulnerability.","secure_code":"from lxml import etree\nimport boto3\n\ndef sync_iot_device_config(device_xml_stream, device_id):\n    s3_client = boto3.client('s3')\n    parser = etree.XMLParser(resolve_entities=False, no_network=True, dtd_validation=False, load_dtd=False)\n    config_tree = etree.parse(device_xml_stream, parser)\n    device_name = config_tree.find('.//device_name').text\n    firmware_ver = config_tree.find('.//firmware').text\n    telemetry_interval = config_tree.find('.//telemetry_interval').text\n    config_data = {'device': device_name, 'firmware': firmware_ver, 'interval': telemetry_interval}\n    s3_client.put_object(Bucket='iot-device-configs', Key=f'{device_id}.json', Body=str(config_data))\n    return {'status': 'synced', 'device': device_name, 'firmware': firmware_ver}"}