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

Language: Python
Severity: Critical
CWE: CWE-611

## Source
1

## Flow
1-6-7

## Sink
7

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

def process_iot_device_config(device_xml_payload):
    s3_client = boto3.client('s3')
    parser = etree.XMLParser(resolve_entities=True, no_network=False)
    device_config = etree.fromstring(device_xml_payload.encode(), parser)
    device_id = device_config.find('.//deviceId').text
    firmware_version = device_config.find('.//firmware').text
    config_data = etree.tostring(device_config, encoding='unicode')
    s3_client.put_object(Bucket='iot-device-configs', Key=f'{device_id}.xml', Body=config_data)
    return {'status': 'configured', 'device': device_id, 'version': firmware_version}
```

## Explanation

The code creates an XML parser with resolve_entities=True and no_network=False, then parses untrusted XML input from IoT devices using etree.fromstring(). This allows XML External Entity (XXE) attacks where malicious XML can read local files, perform SSRF attacks, or cause denial of service through entity expansion bombs.

## Remediation

The fix disables XML external entity processing by setting resolve_entities=False and no_network=True, and additionally disables DTD loading and validation with dtd_validation=False and load_dtd=False. This prevents attackers from injecting malicious entity declarations that could read local files, perform SSRF attacks, or cause denial of service.

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

def process_iot_device_config(device_xml_payload):
    s3_client = boto3.client('s3')
    parser = etree.XMLParser(resolve_entities=False, no_network=True, dtd_validation=False, load_dtd=False)
    device_config = etree.fromstring(device_xml_payload.encode(), parser)
    device_id = device_config.find('.//deviceId').text
    firmware_version = device_config.find('.//firmware').text
    config_data = etree.tostring(device_config, encoding='unicode')
    s3_client.put_object(Bucket='iot-device-configs', Key=f'{device_id}.xml', Body=config_data)
    return {'status': 'configured', 'device': device_id, 'version': firmware_version}
```
