@@ -25,6 +25,9 @@ module XML {
2525
2626 /** Holds if this call to the XML parser resolves entities of the given `kind`. */
2727 abstract predicate resolvesEntities ( EntityKind kind ) ;
28+
29+ /** Gets a reference to a value resulting from parsing the XML. */
30+ js:: DataFlow:: Node getAResult ( ) { none ( ) }
2831 }
2932
3033 /**
@@ -98,10 +101,11 @@ module XML {
98101 * An invocation of `expat.Parser.parse` or `expat.Parser.write`.
99102 */
100103 class ExpatParserInvocation extends ParserInvocation {
104+ js:: DataFlow:: NewNode parser ;
105+
101106 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 ( )
105109 }
106110
107111 override js:: Expr getSourceArgument ( ) { result = getArgument ( 0 ) }
@@ -110,6 +114,10 @@ module XML {
110114 // only internal entities are resolved by default
111115 kind = InternalEntity ( )
112116 }
117+
118+ override js:: DataFlow:: Node getAResult ( ) {
119+ result = parser .getAMemberCall ( "on" ) .getABoundCallbackParameter ( 1 , _)
120+ }
113121 }
114122
115123 /**
@@ -160,4 +168,122 @@ module XML {
160168
161169 override predicate resolvesEntities ( XML:: EntityKind kind ) { kind = InternalEntity ( ) }
162170 }
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+ }
163289}
0 commit comments