# XXE via lxml.etree.fromstring with resolve_entities=True

Language: Python
Severity: Critical
CWE: CWE-611

## Source
4

## Flow
4-7

## Sink
7

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

def process_iot_device_telemetry(xml_payload):
    s3_client = boto3.client('s3')
    parser = etree.XMLParser(resolve_entities=True, no_network=False)
    telemetry_doc = etree.fromstring(xml_payload.encode(), parser)
    device_id = telemetry_doc.find('.//deviceId').text
    sensor_data = telemetry_doc.find('.//sensorReadings').text
    metadata = {'device': device_id, 'readings': sensor_data}
    s3_client.put_object(Bucket='iot-telemetry-bucket', Key=f'data/{device_id}.json', Body=str(metadata))
    return {'status': 'processed', 'device': device_id}
```

## Explanation

The function accepts untrusted XML input (xml_payload) and parses it using lxml.etree with resolve_entities=True and no_network=False. This configuration allows XML External Entity (XXE) attacks where attackers can read local files, perform SSRF attacks, or cause denial of service through entity expansion.

## Remediation

The fix secures the XML parser by setting resolve_entities=False to prevent entity expansion, no_network=True to block external network requests, and dtd_validation=False with load_dtd=False to prevent DTD processing entirely. These settings ensure that malicious XML payloads containing external entity declarations cannot be used to read local files, perform SSRF attacks, or cause denial of service.

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

def process_iot_device_telemetry(xml_payload):
    s3_client = boto3.client('s3')
    parser = etree.XMLParser(resolve_entities=False, no_network=True, dtd_validation=False, load_dtd=False)
    telemetry_doc = etree.fromstring(xml_payload.encode(), parser)
    device_id = telemetry_doc.find('.//deviceId').text
    sensor_data = telemetry_doc.find('.//sensorReadings').text
    metadata = {'device': device_id, 'readings': sensor_data}
    s3_client.put_object(Bucket='iot-telemetry-bucket', Key=f'data/{device_id}.json', Body=str(metadata))
    return {'status': 'processed', 'device': device_id}
```
