1+ /** Provides classes to reason about XSLT injection vulnerabilities. */
2+
13import java
2- import semmle.code.java.dataflow.FlowSources
4+ import semmle.code.java.dataflow.ExternalFlow
35import semmle.code.java.security.XmlParsers
4- import DataFlow
6+ import semmle.code.java.dataflow. DataFlow
57
68/**
7- * A taint-tracking configuration for unvalidated user input that is used in XSLT transformation.
9+ * A data flow sink for unvalidated user input that is used in XSLT transformation.
10+ * Extend this class to add your own XSLT Injection sinks.
811 */
9- class XsltInjectionFlowConfig extends TaintTracking:: Configuration {
10- XsltInjectionFlowConfig ( ) { this = "XsltInjectionFlowConfig" }
11-
12- override predicate isSource ( DataFlow:: Node source ) { source instanceof RemoteFlowSource }
12+ abstract class XsltInjectionSink extends DataFlow:: Node { }
13+
14+ private class DefaultXsltInjectionSinkModel extends SinkModelCsv {
15+ override predicate row ( string row ) {
16+ row =
17+ [
18+ "javax.xml.transform;Transformer;false;transform;;;Argument[-1];xslt" ,
19+ "net.sf.saxon.s9api;XsltTransformer;false;transform;;;Argument[-1];xslt" ,
20+ "net.sf.saxon.s9api;Xslt30Transformer;false;transform;;;Argument[-1];xslt" ,
21+ "net.sf.saxon.s9api;Xslt30Transformer;false;applyTemplates;;;Argument[-1];xslt" ,
22+ "net.sf.saxon.s9api;Xslt30Transformer;false;callFunction;;;Argument[-1];xslt" ,
23+ "net.sf.saxon.s9api;Xslt30Transformer;false;callTemplate;;;Argument[-1];xslt"
24+ ]
25+ }
26+ }
1327
14- override predicate isSink ( DataFlow:: Node sink ) { sink instanceof XsltInjectionSink }
28+ /** A default sink representing methods susceptible to XSLT Injection attacks. */
29+ private class DefaultXsltInjectionSink extends XsltInjectionSink {
30+ DefaultXsltInjectionSink ( ) { sinkNode ( this , "xslt" ) }
31+ }
1532
16- override predicate isSanitizer ( DataFlow:: Node node ) {
17- node .getType ( ) instanceof PrimitiveType or node .getType ( ) instanceof BoxedType
18- }
33+ /**
34+ * A unit class for adding additional taint steps.
35+ *
36+ * Extend this class to add additional taint steps that should apply to the `XsltInjectionFlowConfig`.
37+ */
38+ class XsltInjectionAdditionalTaintStep extends Unit {
39+ /**
40+ * Holds if the step from `node1` to `node2` should be considered a taint
41+ * step for the `XsltInjectionFlowConfig` configuration.
42+ */
43+ abstract predicate step ( DataFlow:: Node node1 , DataFlow:: Node node2 ) ;
44+ }
1945
20- override predicate isAdditionalTaintStep ( DataFlow:: Node node1 , DataFlow:: Node node2 ) {
46+ /** A set of additional taint steps to consider when taint tracking XSLT related data flows. */
47+ private class DefaultXsltInjectionAdditionalTaintStep extends XsltInjectionAdditionalTaintStep {
48+ override predicate step ( DataFlow:: Node node1 , DataFlow:: Node node2 ) {
2149 xmlStreamReaderStep ( node1 , node2 ) or
2250 xmlEventReaderStep ( node1 , node2 ) or
2351 staxSourceStep ( node1 , node2 ) or
@@ -31,95 +59,11 @@ class XsltInjectionFlowConfig extends TaintTracking::Configuration {
3159 }
3260}
3361
34- /** The class `javax.xml.transform.stax.StAXSource`. */
35- class TypeStAXSource extends Class {
36- TypeStAXSource ( ) { this .hasQualifiedName ( "javax.xml.transform.stax" , "StAXSource" ) }
37- }
38-
39- /** The class `javax.xml.transform.dom.DOMSource`. */
40- class TypeDOMSource extends Class {
41- TypeDOMSource ( ) { this .hasQualifiedName ( "javax.xml.transform.dom" , "DOMSource" ) }
42- }
43-
44- /** The interface `javax.xml.transform.Templates`. */
45- class TypeTemplates extends Interface {
46- TypeTemplates ( ) { this .hasQualifiedName ( "javax.xml.transform" , "Templates" ) }
47- }
48-
49- /** The method `net.sf.saxon.s9api.XsltTransformer.transform`. */
50- class XsltTransformerTransformMethod extends Method {
51- XsltTransformerTransformMethod ( ) {
52- this .getDeclaringType ( ) .hasQualifiedName ( "net.sf.saxon.s9api" , "XsltTransformer" ) and
53- this .hasName ( "transform" )
54- }
55- }
56-
57- /** The method `net.sf.saxon.s9api.Xslt30Transformer.transform`. */
58- class Xslt30TransformerTransformMethod extends Method {
59- Xslt30TransformerTransformMethod ( ) {
60- this .getDeclaringType ( ) .hasQualifiedName ( "net.sf.saxon.s9api" , "Xslt30Transformer" ) and
61- this .hasName ( "transform" )
62- }
63- }
64-
65- /** The method `net.sf.saxon.s9api.Xslt30Transformer.applyTemplates`. */
66- class Xslt30TransformerApplyTemplatesMethod extends Method {
67- Xslt30TransformerApplyTemplatesMethod ( ) {
68- this .getDeclaringType ( ) .hasQualifiedName ( "net.sf.saxon.s9api" , "Xslt30Transformer" ) and
69- this .hasName ( "applyTemplates" )
70- }
71- }
72-
73- /** The method `net.sf.saxon.s9api.Xslt30Transformer.callFunction`. */
74- class Xslt30TransformerCallFunctionMethod extends Method {
75- Xslt30TransformerCallFunctionMethod ( ) {
76- this .getDeclaringType ( ) .hasQualifiedName ( "net.sf.saxon.s9api" , "Xslt30Transformer" ) and
77- this .hasName ( "callFunction" )
78- }
79- }
80-
81- /** The method `net.sf.saxon.s9api.Xslt30Transformer.callTemplate`. */
82- class Xslt30TransformerCallTemplateMethod extends Method {
83- Xslt30TransformerCallTemplateMethod ( ) {
84- this .getDeclaringType ( ) .hasQualifiedName ( "net.sf.saxon.s9api" , "Xslt30Transformer" ) and
85- this .hasName ( "callTemplate" )
86- }
87- }
88-
89- /** The class `net.sf.saxon.s9api.XsltCompiler`. */
90- class TypeXsltCompiler extends Class {
91- TypeXsltCompiler ( ) { this .hasQualifiedName ( "net.sf.saxon.s9api" , "XsltCompiler" ) }
92- }
93-
94- /** The class `net.sf.saxon.s9api.XsltExecutable`. */
95- class TypeXsltExecutable extends Class {
96- TypeXsltExecutable ( ) { this .hasQualifiedName ( "net.sf.saxon.s9api" , "XsltExecutable" ) }
97- }
98-
99- /** The class `net.sf.saxon.s9api.XsltPackage`. */
100- class TypeXsltPackage extends Class {
101- TypeXsltPackage ( ) { this .hasQualifiedName ( "net.sf.saxon.s9api" , "XsltPackage" ) }
102- }
103-
104- /** A data flow sink for unvalidated user input that is used in XSLT transformation. */
105- class XsltInjectionSink extends DataFlow:: ExprNode {
106- XsltInjectionSink ( ) {
107- exists ( MethodAccess ma , Method m | m = ma .getMethod ( ) and ma .getQualifier ( ) = this .getExpr ( ) |
108- ma instanceof TransformerTransform or
109- m instanceof XsltTransformerTransformMethod or
110- m instanceof Xslt30TransformerTransformMethod or
111- m instanceof Xslt30TransformerApplyTemplatesMethod or
112- m instanceof Xslt30TransformerCallFunctionMethod or
113- m instanceof Xslt30TransformerCallTemplateMethod
114- )
115- }
116- }
117-
11862/**
11963 * Holds if `n1` to `n2` is a dataflow step that converts between `InputStream` or `Reader` and
12064 * `XMLStreamReader`, i.e. `XMLInputFactory.createXMLStreamReader(tainted)`.
12165 */
122- predicate xmlStreamReaderStep ( ExprNode n1 , ExprNode n2 ) {
66+ private predicate xmlStreamReaderStep ( DataFlow :: Node n1 , DataFlow :: Node n2 ) {
12367 exists ( XmlInputFactoryStreamReader xmlStreamReader |
12468 n1 .asExpr ( ) = xmlStreamReader .getSink ( ) and
12569 n2 .asExpr ( ) = xmlStreamReader
@@ -130,7 +74,7 @@ predicate xmlStreamReaderStep(ExprNode n1, ExprNode n2) {
13074 * Holds if `n1` to `n2` is a dataflow step that converts between `InputStream` or `Reader` and
13175 * `XMLEventReader`, i.e. `XMLInputFactory.createXMLEventReader(tainted)`.
13276 */
133- predicate xmlEventReaderStep ( ExprNode n1 , ExprNode n2 ) {
77+ private predicate xmlEventReaderStep ( DataFlow :: Node n1 , DataFlow :: Node n2 ) {
13478 exists ( XmlInputFactoryEventReader xmlEventReader |
13579 n1 .asExpr ( ) = xmlEventReader .getSink ( ) and
13680 n2 .asExpr ( ) = xmlEventReader
@@ -141,7 +85,7 @@ predicate xmlEventReaderStep(ExprNode n1, ExprNode n2) {
14185 * Holds if `n1` to `n2` is a dataflow step that converts between `XMLStreamReader` or
14286 * `XMLEventReader` and `StAXSource`, i.e. `new StAXSource(tainted)`.
14387 */
144- predicate staxSourceStep ( ExprNode n1 , ExprNode n2 ) {
88+ private predicate staxSourceStep ( DataFlow :: Node n1 , DataFlow :: Node n2 ) {
14589 exists ( ConstructorCall cc | cc .getConstructedType ( ) instanceof TypeStAXSource |
14690 n1 .asExpr ( ) = cc .getAnArgument ( ) and
14791 n2 .asExpr ( ) = cc
@@ -152,7 +96,7 @@ predicate staxSourceStep(ExprNode n1, ExprNode n2) {
15296 * Holds if `n1` to `n2` is a dataflow step that converts between `InputStream` and `Document`,
15397 * i.e. `DocumentBuilder.parse(tainted)`.
15498 */
155- predicate documentBuilderStep ( ExprNode n1 , ExprNode n2 ) {
99+ private predicate documentBuilderStep ( DataFlow :: Node n1 , DataFlow :: Node n2 ) {
156100 exists ( DocumentBuilderParse documentBuilder |
157101 n1 .asExpr ( ) = documentBuilder .getSink ( ) and
158102 n2 .asExpr ( ) = documentBuilder
@@ -163,13 +107,30 @@ predicate documentBuilderStep(ExprNode n1, ExprNode n2) {
163107 * Holds if `n1` to `n2` is a dataflow step that converts between `Document` and `DOMSource`, i.e.
164108 * `new DOMSource(tainted)`.
165109 */
166- predicate domSourceStep ( ExprNode n1 , ExprNode n2 ) {
110+ private predicate domSourceStep ( DataFlow :: Node n1 , DataFlow :: Node n2 ) {
167111 exists ( ConstructorCall cc | cc .getConstructedType ( ) instanceof TypeDOMSource |
168112 n1 .asExpr ( ) = cc .getAnArgument ( ) and
169113 n2 .asExpr ( ) = cc
170114 )
171115}
172116
117+ /**
118+ * Holds if `n1` to `n2` is a dataflow step that converts between `Source` and `Transformer` or
119+ * `Templates`, i.e. `TransformerFactory.newTransformer(tainted)` or
120+ * `TransformerFactory.newTemplates(tainted)`.
121+ */
122+ private predicate newTransformerOrTemplatesStep ( DataFlow:: Node n1 , DataFlow:: Node n2 ) {
123+ exists ( MethodAccess ma , Method m | ma .getMethod ( ) = m |
124+ n1 .asExpr ( ) = ma .getAnArgument ( ) and
125+ n2 .asExpr ( ) = ma and
126+ m .getDeclaringType ( ) instanceof TransformerFactory and
127+ m .hasName ( [ "newTransformer" , "newTemplates" ] ) and
128+ not exists ( TransformerFactoryWithSecureProcessingFeatureFlowConfig conf |
129+ conf .hasFlowToExpr ( ma .getQualifier ( ) )
130+ )
131+ )
132+ }
133+
173134/**
174135 * A data flow configuration for secure processing feature that is enabled on `TransformerFactory`.
175136 */
@@ -207,31 +168,11 @@ private class TransformerFactoryFeatureConfig extends ParserConfig {
207168 }
208169}
209170
210- /**
211- * Holds if `n1` to `n2` is a dataflow step that converts between `Source` and `Transformer` or
212- * `Templates`, i.e. `TransformerFactory.newTransformer(tainted)` or
213- * `TransformerFactory.newTemplates(tainted)`.
214- */
215- predicate newTransformerOrTemplatesStep ( ExprNode n1 , ExprNode n2 ) {
216- exists ( MethodAccess ma , Method m | ma .getMethod ( ) = m |
217- n1 .asExpr ( ) = ma .getAnArgument ( ) and
218- n2 .asExpr ( ) = ma and
219- (
220- m .getDeclaringType ( ) instanceof TransformerFactory and m .hasName ( "newTransformer" )
221- or
222- m .getDeclaringType ( ) instanceof TransformerFactory and m .hasName ( "newTemplates" )
223- ) and
224- not exists ( TransformerFactoryWithSecureProcessingFeatureFlowConfig conf |
225- conf .hasFlowToExpr ( ma .getQualifier ( ) )
226- )
227- )
228- }
229-
230171/**
231172 * Holds if `n1` to `n2` is a dataflow step that converts between `Templates` and `Transformer`,
232173 * i.e. `tainted.newTransformer()`.
233174 */
234- predicate newTransformerFromTemplatesStep ( ExprNode n1 , ExprNode n2 ) {
175+ private predicate newTransformerFromTemplatesStep ( DataFlow :: Node n1 , DataFlow :: Node n2 ) {
235176 exists ( MethodAccess ma , Method m | ma .getMethod ( ) = m |
236177 n1 .asExpr ( ) = ma .getQualifier ( ) and
237178 n2 .asExpr ( ) = ma and
@@ -246,17 +187,12 @@ predicate newTransformerFromTemplatesStep(ExprNode n1, ExprNode n2) {
246187 * `XsltCompiler.loadExecutablePackage(tainted)` or `XsltCompiler.compilePackage(tainted)` or
247188 * `XsltCompiler.loadLibraryPackage(tainted)`.
248189 */
249- predicate xsltCompilerStep ( ExprNode n1 , ExprNode n2 ) {
190+ private predicate xsltCompilerStep ( DataFlow :: Node n1 , DataFlow :: Node n2 ) {
250191 exists ( MethodAccess ma , Method m | ma .getMethod ( ) = m |
251192 n1 .asExpr ( ) = ma .getArgument ( 0 ) and
252193 n2 .asExpr ( ) = ma and
253194 m .getDeclaringType ( ) instanceof TypeXsltCompiler and
254- (
255- m .hasName ( "compile" ) or
256- m .hasName ( "loadExecutablePackage" ) or
257- m .hasName ( "compilePackage" ) or
258- m .hasName ( "loadLibraryPackage" )
259- )
195+ m .hasName ( [ "compile" , "loadExecutablePackage" , "compilePackage" , "loadLibraryPackage" ] )
260196 )
261197}
262198
@@ -265,24 +201,54 @@ predicate xsltCompilerStep(ExprNode n1, ExprNode n2) {
265201 * `XsltTransformer` or `Xslt30Transformer`, i.e. `XsltExecutable.load()` or
266202 * `XsltExecutable.load30()`.
267203 */
268- predicate xsltExecutableStep ( ExprNode n1 , ExprNode n2 ) {
204+ private predicate xsltExecutableStep ( DataFlow :: Node n1 , DataFlow :: Node n2 ) {
269205 exists ( MethodAccess ma , Method m | ma .getMethod ( ) = m |
270206 n1 .asExpr ( ) = ma .getQualifier ( ) and
271207 n2 .asExpr ( ) = ma and
272208 m .getDeclaringType ( ) instanceof TypeXsltExecutable and
273- ( m .hasName ( "load" ) or m . hasName ( "load30" ) )
209+ m .hasName ( [ "load" , "load30" ] )
274210 )
275211}
276212
277213/**
278214 * Holds if `n1` to `n2` is a dataflow step that converts between `XsltPackage` and
279215 * `XsltExecutable`, i.e. `XsltPackage.link()`.
280216 */
281- predicate xsltPackageStep ( ExprNode n1 , ExprNode n2 ) {
217+ private predicate xsltPackageStep ( DataFlow :: Node n1 , DataFlow :: Node n2 ) {
282218 exists ( MethodAccess ma , Method m | ma .getMethod ( ) = m |
283219 n1 .asExpr ( ) = ma .getQualifier ( ) and
284220 n2 .asExpr ( ) = ma and
285221 m .getDeclaringType ( ) instanceof TypeXsltPackage and
286222 m .hasName ( "link" )
287223 )
288224}
225+
226+ /** The class `javax.xml.transform.stax.StAXSource`. */
227+ private class TypeStAXSource extends Class {
228+ TypeStAXSource ( ) { this .hasQualifiedName ( "javax.xml.transform.stax" , "StAXSource" ) }
229+ }
230+
231+ /** The class `javax.xml.transform.dom.DOMSource`. */
232+ private class TypeDOMSource extends Class {
233+ TypeDOMSource ( ) { this .hasQualifiedName ( "javax.xml.transform.dom" , "DOMSource" ) }
234+ }
235+
236+ /** The interface `javax.xml.transform.Templates`. */
237+ private class TypeTemplates extends Interface {
238+ TypeTemplates ( ) { this .hasQualifiedName ( "javax.xml.transform" , "Templates" ) }
239+ }
240+
241+ /** The class `net.sf.saxon.s9api.XsltCompiler`. */
242+ private class TypeXsltCompiler extends Class {
243+ TypeXsltCompiler ( ) { this .hasQualifiedName ( "net.sf.saxon.s9api" , "XsltCompiler" ) }
244+ }
245+
246+ /** The class `net.sf.saxon.s9api.XsltExecutable`. */
247+ private class TypeXsltExecutable extends Class {
248+ TypeXsltExecutable ( ) { this .hasQualifiedName ( "net.sf.saxon.s9api" , "XsltExecutable" ) }
249+ }
250+
251+ /** The class `net.sf.saxon.s9api.XsltPackage`. */
252+ private class TypeXsltPackage extends Class {
253+ TypeXsltPackage ( ) { this .hasQualifiedName ( "net.sf.saxon.s9api" , "XsltPackage" ) }
254+ }
0 commit comments