{"title":"XML External Entity (XXE) via lxml.etree.fromstring()","language":"Python","severity":"High","cwe":"CWE-611","source_lines":[1],"flow_lines":[1,6],"sink_lines":[6],"vulnerable_code":"from lxml import etree\nimport boto3\n\ndef process_iot_device_telemetry(xml_payload):\n    s3_client = boto3.client('s3')\n    try:\n        parsed_doc = etree.fromstring(xml_payload.encode())\n        device_id = parsed_doc.find('.//deviceId').text\n        sensor_data = parsed_doc.find('.//metrics').text\n        timestamp = parsed_doc.find('.//timestamp').text\n        s3_client.put_object(Bucket='iot-telemetry-logs', Key=f'{device_id}/{timestamp}.json', Body=sensor_data)\n        return {'status': 'success', 'device': device_id, 'stored': True}\n    except Exception as err:\n        return {'status': 'error', 'message': str(err)}","explanation":"The function accepts untrusted XML data via the xml_payload parameter and parses it directly using lxml.etree.fromstring() without disabling external entity resolution. This allows attackers to inject malicious XML containing external entity declarations that can read local files, perform SSRF attacks, or cause denial of service.","remediation":"The fix creates a secure XMLParser instance with resolve_entities=False, no_network=True, and load_dtd=False, which prevents the parser from resolving external entities, accessing network resources, or loading external DTDs. This parser is then passed to etree.fromstring() to ensure all XML parsing uses the hardened configuration.","secure_code":"from lxml import etree\nimport boto3\n\ndef process_iot_device_telemetry(xml_payload):\n    s3_client = boto3.client('s3')\n    try:\n        parser = etree.XMLParser(resolve_entities=False, no_network=True, dtd_validation=False, load_dtd=False)\n        parsed_doc = etree.fromstring(xml_payload.encode(), parser=parser)\n        device_id = parsed_doc.find('.//deviceId').text\n        sensor_data = parsed_doc.find('.//metrics').text\n        timestamp = parsed_doc.find('.//timestamp').text\n        s3_client.put_object(Bucket='iot-telemetry-logs', Key=f'{device_id}/{timestamp}.json', Body=sensor_data)\n        return {'status': 'success', 'device': device_id, 'stored': True}\n    except Exception as err:\n        return {'status': 'error', 'message': str(err)}"}