# XML External Entity (XXE) Injection via lxml.etree.parse on Untrusted XML

Language: Python
Severity: Critical
CWE: CWE-611

## Source
5

## Flow
5-7

## Sink
7

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

def process_iot_device_telemetry(device_xml_payload, s3_bucket):
    s3_client = boto3.client('s3')
    parser = etree.XMLParser(resolve_entities=True, no_network=False)
    telemetry_doc = etree.fromstring(device_xml_payload.encode(), parser)
    device_id = telemetry_doc.find('.//DeviceID').text
    sensor_data = telemetry_doc.find('.//SensorReadings').text
    metadata_key = f"telemetry/{device_id}/latest.xml"
    s3_client.put_object(Bucket=s3_bucket, Key=metadata_key, Body=device_xml_payload)
    return {"device": device_id, "data": sensor_data, "stored": metadata_key}
```

## Explanation

The function accepts untrusted XML input from IoT devices and parses it with lxml.etree using a parser explicitly configured with resolve_entities=True and no_network=False. This allows XXE attacks where malicious XML can reference external entities to read local files, perform SSRF attacks, or cause denial of service.

## Remediation

The fix secures the XML parser by setting resolve_entities=False to prevent external entity expansion, no_network=True to block network access during parsing, and explicitly disabling DTD loading and validation. These settings prevent XXE attacks where malicious XML payloads could reference external entities to exfiltrate data or perform SSRF.

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

def process_iot_device_telemetry(device_xml_payload, s3_bucket):
    s3_client = boto3.client('s3')
    parser = etree.XMLParser(resolve_entities=False, no_network=True, dtd_validation=False, load_dtd=False)
    telemetry_doc = etree.fromstring(device_xml_payload.encode(), parser)
    device_id = telemetry_doc.find('.//DeviceID').text
    sensor_data = telemetry_doc.find('.//SensorReadings').text
    metadata_key = f"telemetry/{device_id}/latest.xml"
    s3_client.put_object(Bucket=s3_bucket, Key=metadata_key, Body=device_xml_payload)
    return {"device": device_id, "data": sensor_data, "stored": metadata_key}
```
