# XML Entity Expansion via Exponential Entity Expansion (Billion Laughs)

Language: Python
Severity: High
CWE: CWE-776

## Source
8

## Flow
8-10

## Sink
10

## Vulnerable Code
```python
import xml.etree.ElementTree as ET
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/iot/device/config', methods=['POST'])
def process_device_config():
    device_xml = request.data.decode('utf-8')
    try:
        config_tree = ET.fromstring(device_xml)
        device_id = config_tree.find('device_id').text
        settings = {child.tag: child.text for child in config_tree.find('settings')}
        return jsonify({'status': 'configured', 'device': device_id, 'applied_settings': settings})
    except Exception as e:
        return jsonify({'error': 'Configuration parsing failed', 'details': str(e)}), 400
```

## Explanation

The application accepts untrusted XML data from the HTTP request body and parses it directly using ET.fromstring() without any protection against XML entity expansion attacks. The standard xml.etree.ElementTree parser is vulnerable to Billion Laughs (exponential entity expansion) attacks where malicious XML with nested entity definitions can cause exponential memory consumption and DoS.

## Remediation

The fix replaces the standard `xml.etree.ElementTree` module with `defusedxml.ElementTree`, which provides protection against XML entity expansion attacks (Billion Laughs), external entity attacks (XXE), and other XML-based exploits. The defusedxml library raises an exception when it detects malicious entity definitions, preventing resource exhaustion.

## Secure Code
```python
import defusedxml.ElementTree as ET
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/iot/device/config', methods=['POST'])
def process_device_config():
    device_xml = request.data.decode('utf-8')
    try:
        config_tree = ET.fromstring(device_xml)
        device_id = config_tree.find('device_id').text
        settings = {child.tag: child.text for child in config_tree.find('settings')}
        return jsonify({'status': 'configured', 'device': device_id, 'applied_settings': settings})
    except Exception as e:
        return jsonify({'error': 'Configuration parsing failed', 'details': str(e)}), 400
```
