+
+
+ Processing an unvalidated XSL stylesheet can allow an attacker to change the structure and contents of the resultant XML, include arbitrary files from the file system, or execute arbitrary code.
+
+
+
+
+ This vulnerability can be prevented by not allowing untrusted user input to be passed as an XSL stylesheet.
+ If the application logic necessiates processing untrusted XSL stylesheets, the input should be properly filtered and sanitized before use.
+
+
+
+ In the example below, the XSL stylesheet is controlled by the user and hence leads to a vulnerability.
+
+
+
diff --git a/python/ql/src/experimental/CWE-091/Xslt.ql b/python/ql/src/experimental/CWE-091/Xslt.ql
new file mode 100644
index 000000000000..aa35d92c01a7
--- /dev/null
+++ b/python/ql/src/experimental/CWE-091/Xslt.ql
@@ -0,0 +1,35 @@
+/**
+ * @name XSLT query built from user-controlled sources
+ * @description Building a XSLT query from user-controlled sources is vulnerable to insertion of
+ * malicious XSLT code by the user.
+ * @kind path-problem
+ * @problem.severity error
+ * @precision high
+ * @id py/xslt-injection
+ * @tags security
+ * external/cwe/cwe-643
+ */
+
+import python
+import semmle.python.security.Paths
+/* Sources */
+import semmle.python.web.HttpRequest
+/* Sinks */
+import experimental.semmle.python.security.injection.XSLT
+
+class XSLTInjectionConfiguration extends TaintTracking::Configuration {
+ XSLTInjectionConfiguration() { this = "XSLT injection configuration" }
+
+ override predicate isSource(TaintTracking::Source source) {
+ source instanceof HttpRequestTaintSource
+ }
+
+ override predicate isSink(TaintTracking::Sink sink) {
+ sink instanceof XSLTInjection::XSLTInjectionSink
+ }
+}
+
+from XSLTInjectionConfiguration config, TaintedPathSource src, TaintedPathSink sink
+where config.hasFlowPath(src, sink)
+select sink.getSink(), src, sink, "This XSLT query depends on $@.", src.getSource(),
+ "a user-provided value"
diff --git a/python/ql/src/experimental/CWE-091/xslt.py b/python/ql/src/experimental/CWE-091/xslt.py
new file mode 100644
index 000000000000..1655916c7e06
--- /dev/null
+++ b/python/ql/src/experimental/CWE-091/xslt.py
@@ -0,0 +1,14 @@
+from lxml import etree
+from io import StringIO
+from flask import Flask, request
+
+app = Flask(__name__)
+
+
+@app.route("/xslt")
+def bad():
+ xsltQuery = request.args.get('xml', '')
+ xslt_root = etree.XML(xsltQuery)
+ f = StringIO('