{"title":"XML External Entity (XXE) Injection","language":"Python","severity":"High","cwe":"CWE-611","source_lines":[9],"flow_lines":[9,11],"sink_lines":[11],"vulnerable_code":"from xml.parsers import expat\ndef parse_iot_device_config(raw_xml_data):\n    device_attrs = {}\n    def handle_start(tag, attrs):\n        device_attrs.update(attrs)\n    def handle_char(data):\n        device_attrs['_text'] = device_attrs.get('_text', '') + data\n    p = expat.ParserCreate()\n    p.StartElementHandler = handle_start\n    p.CharacterDataHandler = handle_char\n    p.Parse(raw_xml_data, 1)\n    return device_attrs","explanation":"The function `parse_iot_device_config` accepts raw XML data from an untrusted source (the function parameter `raw_xml_data`) and passes it directly to `expat.ParserCreate()` followed by `p.Parse()` without disabling external entity processing. The Python `expat` parser supports external entity references by default, allowing an attacker to inject a malicious DTD with an external entity declaration (e.g., `<!ENTITY xxe SYSTEM 'file:///etc/passwd'>`) which the parser will resolve, enabling arbitrary file read or SSRF.","remediation":"The fix registers an `ExternalEntityRefHandler` that returns `False` to refuse resolution of any external entities, and an `EntityDeclHandler` that raises an exception if any entity declaration references an external system or public identifier. Together, these two handlers block both the resolution and declaration of external entities, fully mitigating the XXE attack vector while preserving the existing expat-based parsing logic.","secure_code":"from xml.parsers import expat\n\ndef parse_iot_device_config(raw_xml_data):\n    device_attrs = {}\n\n    def handle_start(tag, attrs):\n        device_attrs.update(attrs)\n\n    def handle_char(data):\n        device_attrs['_text'] = device_attrs.get('_text', '') + data\n\n    def handle_external_entity(context, base, system_id, public_id):\n        # Refuse to resolve any external entities to prevent XXE\n        return False\n\n    def handle_entity_decl(entity_name, is_parameter_entity, value,\n                           base, system_id, public_id, notation_name):\n        # Reject any entity declarations that reference external resources\n        if system_id is not None or public_id is not None:\n            raise ValueError(\n                \"External entity declarations are not allowed in IoT device configurations\"\n            )\n\n    p = expat.ParserCreate()\n    p.StartElementHandler = handle_start\n    p.CharacterDataHandler = handle_char\n    # Disable external entity resolution to prevent XXE attacks\n    p.ExternalEntityRefHandler = handle_external_entity\n    p.EntityDeclHandler = handle_entity_decl\n    p.Parse(raw_xml_data, 1)\n    return device_attrs"}