{"title":"XML External Entity (XXE) via lxml resolve_entities=True","language":"Python","severity":"Critical","cwe":"CWE-611","source_lines":[6],"flow_lines":[6,9],"sink_lines":[9],"vulnerable_code":"from lxml import etree\nimport boto3\nfrom flask import request, jsonify\n\ndef process_cloud_deployment_manifest(manifest_xml):\n    s3_client = boto3.client('s3')\n    parser = etree.XMLParser(resolve_entities=True, no_network=False)\n    try:\n        deployment_doc = etree.fromstring(manifest_xml.encode(), parser)\n        service_name = deployment_doc.find('.//ServiceName').text\n        region = deployment_doc.find('.//Region').text\n        instance_type = deployment_doc.find('.//InstanceType').text\n        config_data = {\n            'service': service_name,\n            'region': region,\n            'instance': instance_type,\n            'status': 'parsed'\n        }\n        bucket_key = f\"deployments/{service_name}/config.json\"\n        return jsonify({'success': True, 'config': config_data, 's3_path': bucket_key})\n    except Exception as e:\n        return jsonify({'error': str(e)}), 400","explanation":"The code creates an XML parser with resolve_entities=True and no_network=False, allowing external entity resolution. When untrusted XML from the manifest_xml parameter is parsed using etree.fromstring() with this unsafe parser, attackers can include external entity references 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 resolution, no_network=True to block network access during parsing, and dtd_validation=False and load_dtd=False to prevent DTD loading entirely. These settings ensure that malicious XML payloads containing external entity references cannot be exploited to read files, perform SSRF, or cause denial of service.","secure_code":"from lxml import etree\nimport boto3\nfrom flask import request, jsonify\n\ndef process_cloud_deployment_manifest(manifest_xml):\n    s3_client = boto3.client('s3')\n    parser = etree.XMLParser(resolve_entities=False, no_network=True, dtd_validation=False, load_dtd=False)\n    try:\n        deployment_doc = etree.fromstring(manifest_xml.encode(), parser)\n        service_name = deployment_doc.find('.//ServiceName').text\n        region = deployment_doc.find('.//Region').text\n        instance_type = deployment_doc.find('.//InstanceType').text\n        config_data = {\n            'service': service_name,\n            'region': region,\n            'instance': instance_type,\n            'status': 'parsed'\n        }\n        bucket_key = f\"deployments/{service_name}/config.json\"\n        return jsonify({'success': True, 'config': config_data, 's3_path': bucket_key})\n    except Exception as e:\n        return jsonify({'error': str(e)}), 400"}