=== How to fix it in the Python Standard Library The following noncompliant code is vulnerable to XPath injection because untrusted data is concatenated to an XPath query without prior validation. Although `xml.etree.ElementTree` only supports a subset of XPath syntax, exploitation can still be possible. ==== Noncompliant code example [source,python,diff-id=1,diff-type=noncompliant] ---- from xml.etree import ElementTree from flask import request @app.route('/authenticate') def authenticate(): username = request.args['username'] password = request.args['password'] expression = "./users/user[@name='" + username + "'][@pass='" + password + "']" tree = ElementTree.parse('resources/users.xml') if tree.find(expression) is None: return "Invalid credentials", 401 else: return "Success", 200 ---- //// The above example would be exploitable by using e.g. `username=”admin][.!=”` and `password=”][.!='XXXXX”` This creates the following query: `./users/user[@name='admin][.!='][@pass='][.!='XXXXX']`, where `[.!='][@pass=']` and `[.!='XXXXX']` should match on everything, resulting in authentication as admin. //// ==== Compliant solution [source,python,diff-id=1,diff-type=compliant] ---- import re from xml.etree import ElementTree from flask import request tree = ElementTree.parse('resources/users.xml') @app.route('/authenticate') def authenticate(): username = request.args['username'] password = request.args['password'] if re.match("^[a-zA-Z0-9]*$", username) is None or re.match("^[a-zA-Z0-9]*$", password) is None: return "Username or password contains invalid characters", 400 expression = "./users/user[@name='" + username + "'][@pass='" + password + "']" tree = ElementTree.parse('resources/users.xml') if tree.find(expression) is None: return "Invalid credentials", 401 else: return "Success", 200 ---- === How does this work? As a rule of thumb, the best approach to protect against injections is to systematically ensure that untrusted data cannot break out of the initially intended logic. include::../../common/fix/parameterized-queries.adoc[] It is not possible to construct parameterized queries using only the Python Standard Library. + Please use https://pypi.org/project/lxml/[lxml] instead, which allows for parameterized queries using the `ElementTree.xpath()` method. include::../../common/fix/validation.adoc[] In the example, we ensure that the username and password only contain alphanumeric characters by doing a regex match before executing the XPath query.