HIGH xml external entitiesflaskbasic auth

Xml External Entities in Flask with Basic Auth

Xml External Entities in Flask with Basic Auth — how this specific combination creates or exposes the vulnerability

An XML External Entity (XXE) injection occurs when an application processes XML input and allows an attacker to define external entities that can read local files, trigger SSRF, or cause denial of service. In Flask, this typically arises when you use XML-parsing libraries such as lxml or xml.etree on user-supplied data without disabling external entity resolution. When Basic Auth is used, the client sends an Authorization header (e.g., Authorization: Basic base64(username:password)) with the request. The combination of accepting XML input and relying on Basic Auth for access control can create a misleading sense of protection: the presence of credentials does not change how the XML parser behaves, and an authenticated or unauthenticated attacker can still supply malicious XML if the endpoint is reachable.

Consider a Flask endpoint that accepts XML to configure or enrich a request. If the endpoint parses XML without disabling external entities, an attacker can provide an XML payload that references a file:// URL to read /etc/passwd, or an http:// URL to an internal SSRF target. Basic Auth might limit who can reach the endpoint in your design, but if the endpoint is exposed (for example, due to misconfigured routing or a proxy), the XXE vector remains. Moreover, in an unauthenticated scan, middleBrick tests the unauthenticated attack surface; if Basic Auth is expected but not enforced at the parser boundary, credentials may be omitted, and the parser will still process external entities. The risk is compounded when XML is used to construct requests to internal services, enabling SSRF via external entities, while the expectation that Basic Auth protects the endpoint may delay detection.

Real-world examples include parsing uploaded configuration files or SOAP messages. An attacker might send:

<?xml version="1.0"?>
<!DOCTYPE foo [ <!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>>
<root>&xxe;</root>

If the parser resolves &xxe;, the file contents may be returned or forwarded. MiddleBrick’s checks for Data Exposure and Input Validation highlight whether XML parsers are resolving external entities, and findings may map to OWASP API Top 10 A05 (2023) and related compliance frameworks.

Basic Auth-Specific Remediation in Flask — concrete code fixes

To mitigate XXE in Flask when using Basic Auth, focus on disabling external entity resolution in your XML parser and ensuring credentials are validated before processing sensitive operations. Below are concrete, safe patterns.

1. Secure XML parsing with defusedxml

Use defusedxml to prevent entity expansion and external file access. This is the recommended approach because it removes dangerous features at the parser level.

from defusedxml.ElementTree import fromstring

@app.route('/process', methods=['POST'])
def process_xml():
    xml_data = request.get_data()
    try:
        tree = fromstring(xml_data)  # safe: no external entities
        # process tree safely
        return {'status': 'ok'}, 200
    except Exception as e:
        return {'error': str(e)}, 400

2. Disable entities explicitly with lxml (if you must use lxml)

If you rely on lxml, configure the parser to disable DTDs and external entities.

from lxml import etree

parser = etree.XMLParser(resolve_entities=False, no_network=True, dtd_load=False, load_dtd=False)

@app.route('/process-lxml', methods=['POST'])
def process_lxml():
    xml_data = request.get_data()
    try:
        tree = etree.fromstring(xml_data, parser=parser)
        # process tree safely
        return {'status': 'ok'}, 200
    except Exception as e:
        return {'error': str(e)}, 400

3. Enforce Basic Auth before parsing, using Flask-HTTPAuth

Ensure credentials are verified and tied to the request before any XML processing. This does not prevent XXE on its own, but ensures that only authorized users can invoke the parser.

from flask import Flask, request, jsonify
from flask_httpauth import HTTPBasicAuth

app = Flask(__name__)
auth = HTTPBasicAuth()

USERS = {
    "admin": "secret",
}

@auth.verify_password
def verify_password(username, password):
    if username in USERS and USERS[username] == password:
        return username

@app.route('/secure-process', methods=['POST'])
@auth.login_required
def secure_process():
    xml_data = request.get_data()
    # Use a safe parser here, e.g., defusedxml
    try:
        # Example with defusedxml
        from defusedxml.ElementTree import fromstring
        tree = fromstring(xml_data)
        # process tree
        return jsonify({'user': auth.current_user(), 'status': 'ok'}), 200
    except Exception as e:
        return jsonify({'error': str(e)}), 400

4. Validate and restrict input size

Limit XML size and reject DOCTYPE declarations to reduce attack surface.

@app.route('/validate-process', methods=['POST'])
@auth.login_required
def validate_process():
    # Limit payload to 128 KiB
    if len(request.data) > 128 * 1024:
        return jsonify({'error': 'payload too large'}), 413
    # Reject inline DOCTYPE
    if b'

These steps ensure that authentication does not create a false sense of security and that XML parsing is hardened against XXE. MiddleBrick scans can verify that external entities are not resolved and that Basic Auth is properly enforced before sensitive operations.

Frequently Asked Questions

Does using Basic Auth prevent XXE in Flask?
No. Basic Auth controls access to the endpoint but does not change how an XML parser resolves external entities. You must disable DTDs and external entities in the parser (e.g., with defusedxml or a secured lxml parser) to prevent XXE.
Can an authenticated XXE be used for SSRF or file disclosure?
Yes. If an endpoint parses XML with external entities enabled, an attacker can read files (file://) or reach internal services (http://) even when requests include valid Basic Auth credentials. Always treat XML input as untrusted and disable entity resolution regardless of auth.