{"title":"XML Billion Laughs Entity Expansion via lxml.etree.XMLParser(resolve_entities=True)","language":"Python","severity":"High","cwe":"CWE-611","source_lines":[3],"flow_lines":[3,6,8],"sink_lines":[8],"vulnerable_code":"from lxml import etree\nimport boto3\n\ndef process_iot_device_manifest(manifest_xml, device_id):\n    s3_client = boto3.client('s3')\n    xml_parser = etree.XMLParser(resolve_entities=True, no_network=False)\n    try:\n        device_config = etree.fromstring(manifest_xml.encode(), parser=xml_parser)\n        firmware_version = device_config.find('.//firmware').text\n        telemetry_interval = device_config.find('.//telemetry_interval').text\n        s3_client.put_object(Bucket='iot-device-configs', Key=f'devices/{device_id}/manifest.xml', Body=manifest_xml)\n        return {'device_id': device_id, 'firmware': firmware_version, 'interval': telemetry_interval}\n    except etree.XMLSyntaxError as err:\n        return {'error': 'Invalid manifest format', 'device_id': device_id}","explanation":"The function accepts untrusted XML input (manifest_xml) from IoT devices and parses it with resolve_entities=True, enabling XML External Entity (XXE) and Billion Laughs attacks. The parser expands entities before validation, allowing attackers to cause denial of service through exponential entity expansion or exfiltrate local files.","remediation":"The fix disables entity resolution by setting resolve_entities=False, prevents network access with no_network=True, and disables DTD loading and validation with dtd_validation=False and load_dtd=False. This prevents both Billion Laughs (exponential entity expansion) and XXE attacks by ensuring no entities are resolved and no external resources are fetched during parsing.","secure_code":"from lxml import etree\nimport boto3\n\ndef process_iot_device_manifest(manifest_xml, device_id):\n    s3_client = boto3.client('s3')\n    xml_parser = etree.XMLParser(resolve_entities=False, no_network=True, dtd_validation=False, load_dtd=False)\n    try:\n        device_config = etree.fromstring(manifest_xml.encode(), parser=xml_parser)\n        firmware_version = device_config.find('.//firmware').text\n        telemetry_interval = device_config.find('.//telemetry_interval').text\n        s3_client.put_object(Bucket='iot-device-configs', Key=f'devices/{device_id}/manifest.xml', Body=manifest_xml)\n        return {'device_id': device_id, 'firmware': firmware_version, 'interval': telemetry_interval}\n    except etree.XMLSyntaxError as err:\n        return {'error': 'Invalid manifest format', 'device_id': device_id}"}