=== How to fix it in lxml The following noncompliant code is vulnerable to XPath injections because untrusted data is concatenated to an XPath query without prior validation. ==== Noncompliant code example [source,python,diff-id=1,diff-type=noncompliant] ---- from flask import request from lxml import etree @app.route('/authenticate') def authenticate(): username = request.args['username'] password = request.args['password'] expression = "./users/user[@name='" + username + "' and @pass='" + password + "']" tree = etree.parse('resources/users.xml') if tree.find(expression) is None: return "Invalid credentials", 401 else: return "Success", 200 ---- ==== Compliant solution [source,python,diff-id=1,diff-type=compliant] ---- from flask import request from lxml import etree @app.route('/authenticate') def authenticate(): username = request.args['username'] password = request.args['password'] expression = "./users/user[@name=$username and @pass=$password]" tree = etree.parse('resources/users.xml') if tree.xpath(expression, username=username, password=password) 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[] In the example, the username and password are passed as https://lxml.de/xpathxslt.html#:~:text=The%20xpath()%20method%20has%20support%20for%20XPath%20variables%3A[XPath variables] rather than concatenated to the XPath query. By using a parameterized query, injection is successfully prevented.