# XML External Entity (XXE) Injection via lxml.etree.fromstring()

Language: Python
Severity: High
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)
    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, 'timestamp': telemetry_doc.get('timestamp')}
    s3_client.put_object(Bucket='iot-telemetry-bucket', Key=f'devices/{device_id}/data.xml', Body=sensor_data, Metadata=metadata)
    return {'status': 'processed', 'device': device_id, 'data_size': len(sensor_data)}
```

## Explanation

The function accepts untrusted XML input (xml_payload) and parses it with lxml.etree using an XMLParser configured with resolve_entities=True. This allows attackers to inject XML External Entity (XXE) references that can lead to local file disclosure, SSRF attacks, or denial of service.

## Remediation

The fix secures the XMLParser by setting resolve_entities=False to prevent entity expansion, no_network=True to block network-based entity resolution, and dtd_validation=False with load_dtd=False to prevent DTD loading entirely. These settings ensure that any XXE payloads embedded in the XML input will not be processed or resolved.

## 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, 'timestamp': telemetry_doc.get('timestamp')}
    s3_client.put_object(Bucket='iot-telemetry-bucket', Key=f'devices/{device_id}/data.xml', Body=sensor_data, Metadata=metadata)
    return {'status': 'processed', 'device': device_id, 'data_size': len(sensor_data)}
```
