@@ -185,38 +185,15 @@ module TaintTracking {
185185
186186 override predicate step ( DataFlow:: Node pred , DataFlow:: Node succ ) {
187187 succ = this and
188- (
189- exists ( Expr e , Expr f | e = this .asExpr ( ) and f = pred .asExpr ( ) |
190- // arrays with tainted elements and objects with tainted property names are tainted
191- e .( ArrayExpr ) .getAnElement ( ) = f or
192- exists ( Property prop | e .( ObjectExpr ) .getAProperty ( ) = prop |
193- prop .isComputed ( ) and f = prop .getNameExpr ( )
194- )
195- or
196- // awaiting a tainted expression gives a tainted result
197- e .( AwaitExpr ) .getOperand ( ) = f
188+ exists ( Expr e , Expr f | e = this .asExpr ( ) and f = pred .asExpr ( ) |
189+ // arrays with tainted elements and objects with tainted property names are tainted
190+ e .( ArrayExpr ) .getAnElement ( ) = f or
191+ exists ( Property prop | e .( ObjectExpr ) .getAProperty ( ) = prop |
192+ prop .isComputed ( ) and f = prop .getNameExpr ( )
198193 )
199194 or
200- // `array.map(function (elt, i, ary) { ... })`: if `array` is tainted, then so are
201- // `elt` and `ary`; similar for `forEach`
202- exists ( MethodCallExpr m , Function f , int i , SimpleParameter p |
203- ( m .getMethodName ( ) = "map" or m .getMethodName ( ) = "forEach" ) and
204- ( i = 0 or i = 2 ) and
205- m .getArgument ( 0 ) .analyze ( ) .getAValue ( ) .( AbstractFunction ) .getFunction ( ) = f and
206- p = f .getParameter ( i ) and
207- this = DataFlow:: parameterNode ( p ) and
208- pred .asExpr ( ) = m .getReceiver ( )
209- )
210- or
211- // `array.map` with tainted return value in callback
212- exists ( MethodCallExpr m , Function f |
213- this .asExpr ( ) = m and
214- m .getMethodName ( ) = "map" and
215- m .getArgument ( 0 ) = f and // Require the argument to be a closure to avoid spurious call/return flow
216- pred = f .getAReturnedExpr ( ) .flow ( ) )
217- or
218- // `array.push(e)`: if `e` is tainted, then so is `array`
219- succ .( DataFlow:: SourceNode ) .getAMethodCall ( "push" ) .getAnArgument ( ) = pred
195+ // awaiting a tainted expression gives a tainted result
196+ e .( AwaitExpr ) .getOperand ( ) = f
220197 )
221198 or
222199 // reading from a tainted object yields a tainted result
@@ -233,6 +210,61 @@ module TaintTracking {
233210 }
234211 }
235212
213+ /**
214+ * A taint propagating data flow edge caused by the builtin array functions.
215+ */
216+ private class ArrayFunctionTaintStep extends AdditionalTaintStep {
217+ DataFlow:: CallNode call ;
218+
219+ ArrayFunctionTaintStep ( ) {
220+ this = call
221+ }
222+
223+ override predicate step ( DataFlow:: Node pred , DataFlow:: Node succ ) {
224+ // `array.map(function (elt, i, ary) { ... })`: if `array` is tainted, then so are
225+ // `elt` and `ary`; similar for `forEach`
226+ exists ( string name , Function f , int i |
227+ ( name = "map" or name = "forEach" ) and
228+ ( i = 0 or i = 2 ) and
229+ call .getArgument ( 0 ) .analyze ( ) .getAValue ( ) .( AbstractFunction ) .getFunction ( ) = f and
230+ pred .( DataFlow:: SourceNode ) .getAMethodCall ( name ) = call and
231+ succ = DataFlow:: parameterNode ( f .getParameter ( i ) )
232+ )
233+ or
234+ // `array.map` with tainted return value in callback
235+ exists ( DataFlow:: FunctionNode f |
236+ call .( DataFlow:: MethodCallNode ) .getMethodName ( ) = "map" and
237+ call .getArgument ( 0 ) = f and // Require the argument to be a closure to avoid spurious call/return flow
238+ pred = f .getAReturn ( ) and
239+ succ = call
240+ )
241+ or
242+ // `array.push(e)`, `array.unshift(e)`: if `e` is tainted, then so is `array`.
243+ exists ( string name |
244+ name = "push" or
245+ name = "unshift" |
246+ pred = call .getAnArgument ( ) and
247+ succ .( DataFlow:: SourceNode ) .getAMethodCall ( name ) = call
248+ )
249+ or
250+ // `e = array.pop()`, `e = array.shift()`, or similar: if `array` is tainted, then so is `e`.
251+ exists ( string name |
252+ name = "pop" or
253+ name = "shift" or
254+ name = "slice" or
255+ name = "splice" |
256+ call .( DataFlow:: MethodCallNode ) .calls ( pred , name ) and
257+ succ = call
258+ )
259+ or
260+ // `e = Array.from(x)`: if `x` is tainted, then so is `e`.
261+ call = DataFlow:: globalVarRef ( "Array" ) .getAPropertyRead ( "from" ) .getACall ( ) and
262+ pred = call .getAnArgument ( ) and
263+ succ = call
264+ }
265+
266+ }
267+
236268 /**
237269 * A taint propagating data flow edge for assignments of the form `o[k] = v`, where
238270 * `k` is not a constant and `o` refers to some object literal; in this case, we consider
0 commit comments