@@ -68,7 +68,7 @@ module ArrayTaintTracking {
68
68
succ = call
69
69
or
70
70
// `e = Array.from(x)`: if `x` is tainted, then so is `e`.
71
- call = DataFlow :: globalVarRef ( "Array" ) . getAPropertyRead ( "from" ) . getACall ( ) and
71
+ call = arrayFromCall ( ) and
72
72
pred = call .getAnArgument ( ) and
73
73
succ = call
74
74
or
@@ -79,6 +79,11 @@ module ArrayTaintTracking {
79
79
call .( DataFlow:: MethodCallNode ) .getMethodName ( ) = "concat" and
80
80
succ = call and
81
81
pred = call .getAnArgument ( )
82
+ or
83
+ // find
84
+ // `e = arr.find(callback)`
85
+ call = arrayFindCall ( pred ) and
86
+ succ = call
82
87
}
83
88
}
84
89
@@ -97,7 +102,7 @@ private module ArrayDataFlow {
97
102
DataFlow:: Node pred , DataFlow:: Node succ , string fromProp , string toProp
98
103
) {
99
104
exists ( DataFlow:: CallNode call |
100
- call = DataFlow :: globalVarRef ( "Array" ) . getAMemberCall ( "from" ) and
105
+ call = arrayFromCall ( ) and
101
106
pred = call .getArgument ( 0 ) and
102
107
succ = call and
103
108
fromProp = arrayLikeElement ( ) and
@@ -297,4 +302,108 @@ private module ArrayDataFlow {
297
302
)
298
303
}
299
304
}
305
+
306
+ /**
307
+ * A step modelling that elements from an array `arr` are received by calling `find`.
308
+ */
309
+ private class ArrayFindStep extends DataFlow:: SharedFlowStep {
310
+ override predicate loadStep ( DataFlow:: Node pred , DataFlow:: Node succ , string prop ) {
311
+ exists ( DataFlow:: CallNode call |
312
+ call = arrayFindCall ( pred ) and
313
+ succ = call and
314
+ prop = arrayElement ( )
315
+ )
316
+ }
317
+ }
318
+ }
319
+
320
+ private import ArrayLibraries
321
+
322
+ /**
323
+ * Classes and predicates modelling various libraries that work on arrays or array-like structures.
324
+ */
325
+ private module ArrayLibraries {
326
+ private import DataFlow:: PseudoProperties
327
+
328
+ /**
329
+ * Gets a call to `Array.from` or a polyfill implementing the same functionality.
330
+ */
331
+ DataFlow:: CallNode arrayFromCall ( ) {
332
+ result = DataFlow:: globalVarRef ( "Array" ) .getAMemberCall ( "from" )
333
+ or
334
+ result = DataFlow:: moduleImport ( "array-from" ) .getACall ( )
335
+ }
336
+
337
+ /**
338
+ * Gets a call to `Array.prototype.find` or a polyfill implementing the same functionality.
339
+ */
340
+ DataFlow:: CallNode arrayFindCall ( DataFlow:: Node array ) {
341
+ result .( DataFlow:: MethodCallNode ) .getMethodName ( ) = "find" and
342
+ array = result .getReceiver ( )
343
+ or
344
+ result = DataFlow:: moduleImport ( [ "array.prototype.find" , "array-find" ] ) .getACall ( ) and
345
+ array = result .getArgument ( 0 )
346
+ }
347
+
348
+ /**
349
+ * A taint step through the `arrify` library, or other libraries that (maybe) convert values into arrays.
350
+ */
351
+ private class ArrayifyStep extends TaintTracking:: SharedTaintStep {
352
+ override predicate step ( DataFlow:: Node pred , DataFlow:: Node succ ) {
353
+ exists ( API:: CallNode call | call = API:: moduleImport ( [ "arrify" , "array-ify" ] ) .getACall ( ) |
354
+ pred = call .getArgument ( 0 ) and succ = call
355
+ )
356
+ }
357
+ }
358
+
359
+ /**
360
+ * A call to a library that copies the elements of an array into another array.
361
+ * E.g. `array-union` that creates a union of multiple arrays, or `array-uniq` that creates an array with unique elements.
362
+ */
363
+ DataFlow:: CallNode arrayCopyCall ( DataFlow:: Node array ) {
364
+ result = API:: moduleImport ( [ "array-union" , "array-uniq" , "uniq" ] ) .getACall ( ) and
365
+ array = result .getAnArgument ( )
366
+ }
367
+
368
+ /**
369
+ * A taint step for a library that copies the elements of an array into another array.
370
+ */
371
+ private class ArrayCopyTaint extends TaintTracking:: SharedTaintStep {
372
+ override predicate step ( DataFlow:: Node pred , DataFlow:: Node succ ) {
373
+ exists ( DataFlow:: CallNode call |
374
+ call = arrayCopyCall ( pred ) and
375
+ succ = call
376
+ )
377
+ }
378
+ }
379
+
380
+ /**
381
+ * A loadStoreStep for a library that copies the elements of an array into another array.
382
+ */
383
+ private class ArrayCopyLoadStore extends DataFlow:: SharedFlowStep {
384
+ override predicate loadStoreStep ( DataFlow:: Node pred , DataFlow:: Node succ , string prop ) {
385
+ exists ( DataFlow:: CallNode call |
386
+ call = arrayCopyCall ( pred ) and
387
+ succ = call and
388
+ prop = arrayElement ( )
389
+ )
390
+ }
391
+ }
392
+
393
+ /**
394
+ * A taint step through a call to `Array.prototype.flat` or a polyfill implementing array flattening.
395
+ */
396
+ private class ArrayFlatStep extends TaintTracking:: SharedTaintStep {
397
+ override predicate step ( DataFlow:: Node pred , DataFlow:: Node succ ) {
398
+ exists ( DataFlow:: CallNode call | succ = call |
399
+ call .( DataFlow:: MethodCallNode ) .getMethodName ( ) = "flat" and
400
+ pred = call .getReceiver ( )
401
+ or
402
+ call =
403
+ API:: moduleImport ( [ "array-flatten" , "arr-flatten" , "flatten" , "array.prototype.flat" ] )
404
+ .getACall ( ) and
405
+ pred = call .getAnArgument ( )
406
+ )
407
+ }
408
+ }
300
409
}
0 commit comments