# XXE via lxml External Entity Resolution

Language: Python
Severity: High
CWE: CWE-611

## Source
5

## Flow
5-6-7

## Sink
7

## Vulnerable Code
```python
from lxml import etree
import requests

def process_iot_device_manifest(manifest_url):
    device_xml = requests.get(manifest_url).content
    parser = etree.XMLParser(resolve_entities=True, no_network=False)
    manifest_tree = etree.fromstring(device_xml, parser)
    device_id = manifest_tree.find('.//deviceID').text
    firmware_ver = manifest_tree.find('.//firmwareVersion').text
    capabilities = [cap.text for cap in manifest_tree.findall('.//capability')]
    return {'id': device_id, 'firmware': firmware_ver, 'caps': capabilities}
```

## Explanation

The code fetches untrusted XML content from a remote URL and parses it with an XMLParser configured with resolve_entities=True and no_network=False, enabling XXE attacks. An attacker can provide a malicious manifest URL containing external entity declarations that reference local files or internal network resources, leading to information disclosure or SSRF.

## Remediation

The fix secures the XMLParser by setting resolve_entities=False to prevent external entity expansion, no_network=True to block network access during parsing, and dtd_validation=False with load_dtd=False to prevent DTD loading entirely. These settings ensure that even if a malicious XML document contains external entity declarations, they will not be resolved or fetched.

## Secure Code
```python
from lxml import etree
import requests

def process_iot_device_manifest(manifest_url):
    device_xml = requests.get(manifest_url).content
    parser = etree.XMLParser(resolve_entities=False, no_network=True, dtd_validation=False, load_dtd=False)
    manifest_tree = etree.fromstring(device_xml, parser)
    device_id = manifest_tree.find('.//deviceID').text
    firmware_ver = manifest_tree.find('.//firmwareVersion').text
    capabilities = [cap.text for cap in manifest_tree.findall('.//capability')]
    return {'id': device_id, 'firmware': firmware_ver, 'caps': capabilities}
```
