@@ -25,6 +25,9 @@ module XML {
25
25
26
26
/** Holds if this call to the XML parser resolves entities of the given `kind`. */
27
27
abstract predicate resolvesEntities ( EntityKind kind ) ;
28
+
29
+ /** Gets a reference to a value resulting from parsing the XML. */
30
+ js:: DataFlow:: Node getAResult ( ) { none ( ) }
28
31
}
29
32
30
33
/**
@@ -98,10 +101,11 @@ module XML {
98
101
* An invocation of `expat.Parser.parse` or `expat.Parser.write`.
99
102
*/
100
103
class ExpatParserInvocation extends ParserInvocation {
104
+ js:: DataFlow:: NewNode parser ;
105
+
101
106
ExpatParserInvocation ( ) {
102
- exists ( string m | m = "parse" or m = "write" |
103
- this = moduleMethodCall ( "node-expat" , "Parser" , m )
104
- )
107
+ parser = js:: DataFlow:: moduleMember ( "node-expat" , "Parser" ) .getAnInstantiation ( ) and
108
+ this = parser .getAMemberCall ( [ "parse" , "write" ] ) .asExpr ( )
105
109
}
106
110
107
111
override js:: Expr getSourceArgument ( ) { result = getArgument ( 0 ) }
@@ -110,6 +114,10 @@ module XML {
110
114
// only internal entities are resolved by default
111
115
kind = InternalEntity ( )
112
116
}
117
+
118
+ override js:: DataFlow:: Node getAResult ( ) {
119
+ result = parser .getAMemberCall ( "on" ) .getABoundCallbackParameter ( 1 , _)
120
+ }
113
121
}
114
122
115
123
/**
@@ -160,4 +168,122 @@ module XML {
160
168
161
169
override predicate resolvesEntities ( XML:: EntityKind kind ) { kind = InternalEntity ( ) }
162
170
}
171
+
172
+ /**
173
+ * An invocation of `xml2js`.
174
+ */
175
+ private class Xml2JSInvocation extends XML:: ParserInvocation {
176
+ js:: DataFlow:: CallNode call ;
177
+
178
+ Xml2JSInvocation ( ) {
179
+ exists ( js:: API:: Node imp | imp = js:: API:: moduleImport ( "xml2js" ) |
180
+ call = [ imp , imp .getMember ( "Parser" ) .getInstance ( ) ] .getMember ( "parseString" ) .getACall ( ) and
181
+ this = call .asExpr ( )
182
+ )
183
+ }
184
+
185
+ override js:: Expr getSourceArgument ( ) { result = getArgument ( 0 ) }
186
+
187
+ override predicate resolvesEntities ( XML:: EntityKind kind ) {
188
+ // sax-js (the parser used) does not expand entities.
189
+ none ( )
190
+ }
191
+
192
+ override js:: DataFlow:: Node getAResult ( ) {
193
+ result = call .getABoundCallbackParameter ( call .getNumArgument ( ) - 1 , 1 )
194
+ }
195
+ }
196
+
197
+ /**
198
+ * An invocation of `sax`.
199
+ */
200
+ private class SaxInvocation extends XML:: ParserInvocation {
201
+ js:: DataFlow:: InvokeNode parser ;
202
+
203
+ SaxInvocation ( ) {
204
+ exists ( js:: API:: Node imp | imp = js:: API:: moduleImport ( "sax" ) |
205
+ parser = imp .getMember ( "parser" ) .getACall ( )
206
+ or
207
+ parser = imp .getMember ( "SAXParser" ) .getAnInstantiation ( )
208
+ ) and
209
+ this = parser .getAMemberCall ( "write" ) .asExpr ( )
210
+ }
211
+
212
+ override js:: Expr getSourceArgument ( ) { result = getArgument ( 0 ) }
213
+
214
+ override predicate resolvesEntities ( XML:: EntityKind kind ) {
215
+ // sax-js does not expand entities.
216
+ none ( )
217
+ }
218
+
219
+ override js:: DataFlow:: Node getAResult ( ) {
220
+ result =
221
+ parser
222
+ .getAPropertyWrite ( any ( string s | s .matches ( "on%" ) ) )
223
+ .getRhs ( )
224
+ .getAFunctionValue ( )
225
+ .getAParameter ( )
226
+ }
227
+ }
228
+
229
+ /**
230
+ * An invocation of `xml-js`.
231
+ */
232
+ private class XmlJSInvocation extends XML:: ParserInvocation {
233
+ XmlJSInvocation ( ) {
234
+ this =
235
+ js:: DataFlow:: moduleMember ( "xml-js" , [ "xml2json" , "xml2js" , "json2xml" , "js2xml" ] )
236
+ .getACall ( )
237
+ .asExpr ( )
238
+ }
239
+
240
+ override js:: Expr getSourceArgument ( ) { result = getArgument ( 0 ) }
241
+
242
+ override predicate resolvesEntities ( XML:: EntityKind kind ) {
243
+ // xml-js does not expand custom entities.
244
+ none ( )
245
+ }
246
+
247
+ override js:: DataFlow:: Node getAResult ( ) { result .asExpr ( ) = this }
248
+ }
249
+
250
+ /**
251
+ * An invocation of `htmlparser2`.
252
+ */
253
+ private class HtmlParser2Invocation extends XML:: ParserInvocation {
254
+ js:: DataFlow:: NewNode parser ;
255
+
256
+ HtmlParser2Invocation ( ) {
257
+ parser = js:: DataFlow:: moduleMember ( "htmlparser2" , "Parser" ) .getAnInstantiation ( ) and
258
+ this = parser .getAMemberCall ( "write" ) .asExpr ( )
259
+ }
260
+
261
+ override js:: Expr getSourceArgument ( ) { result = getArgument ( 0 ) }
262
+
263
+ override predicate resolvesEntities ( XML:: EntityKind kind ) {
264
+ // htmlparser2 does not expand entities.
265
+ none ( )
266
+ }
267
+
268
+ override js:: DataFlow:: Node getAResult ( ) {
269
+ result =
270
+ parser
271
+ .getArgument ( 0 )
272
+ .getALocalSource ( )
273
+ .getAPropertySource ( )
274
+ .getAFunctionValue ( )
275
+ .getAParameter ( )
276
+ }
277
+ }
278
+
279
+ private class XMLParserTaintStep extends js:: TaintTracking:: AdditionalTaintStep {
280
+ XML:: ParserInvocation parser ;
281
+
282
+ XMLParserTaintStep ( ) { this .asExpr ( ) = parser }
283
+
284
+ override predicate step ( js:: DataFlow:: Node pred , js:: DataFlow:: Node succ ) {
285
+ pred .asExpr ( ) = parser .getSourceArgument ( ) and
286
+ succ = parser .getAResult ( )
287
+ }
288
+ }
163
289
}
0 commit comments