@@ -144,7 +144,13 @@ module LodashUnderscore {
144144 name = [ "union" , "zip" ] and
145145 pred = call .getAnArgument ( ) and
146146 succ = call
147- or
147+ )
148+ }
149+
150+ private predicate underscoreTaintStepLegacy ( DataFlow:: Node pred , DataFlow:: Node succ ) {
151+ exists ( string name , DataFlow:: CallNode call |
152+ call = any ( Member member | member .getName ( ) = name ) .getACall ( )
153+ |
148154 name =
149155 [ "each" , "map" , "every" , "some" , "max" , "min" , "sortBy" , "partition" , "mapObject" , "tap" ] and
150156 pred = call .getArgument ( 0 ) and
@@ -168,6 +174,169 @@ module LodashUnderscore {
168174 underscoreTaintStep ( pred , succ )
169175 }
170176 }
177+
178+ private class UnderscoreTaintStepLegacy extends TaintTracking:: LegacyTaintStep {
179+ override predicate step ( DataFlow:: Node pred , DataFlow:: Node succ ) {
180+ underscoreTaintStepLegacy ( pred , succ )
181+ }
182+ }
183+
184+ private class LodashEach extends DataFlow:: SummarizedCallable {
185+ LodashEach ( ) { this = "_.each-like" }
186+
187+ override DataFlow:: CallNode getACall ( ) {
188+ result = member ( [ "each" , "eachRight" , "forEach" , "forEachRight" , "every" , "some" ] ) .getACall ( )
189+ }
190+
191+ override predicate propagatesFlow ( string input , string output , boolean preservesValue ) {
192+ preservesValue = true and
193+ input = "Argument[0].ArrayElement" and
194+ output = "Argument[1].Parameter[0]"
195+ }
196+ }
197+
198+ private class LodashMap extends DataFlow:: SummarizedCallable {
199+ LodashMap ( ) { this = "_.map" }
200+
201+ override DataFlow:: CallNode getACall ( ) { result = member ( "map" ) .getACall ( ) }
202+
203+ override predicate propagatesFlow ( string input , string output , boolean preservesValue ) {
204+ (
205+ input = "Argument[0].ArrayElement" and
206+ output = "Argument[1].Parameter[0]"
207+ or
208+ input = "Argument[1].ReturnValue" and
209+ output = "ReturnValue.ArrayElement"
210+ ) and
211+ preservesValue = true
212+ }
213+ }
214+
215+ private class LodashFlatMap extends DataFlow:: SummarizedCallable {
216+ LodashFlatMap ( ) { this = "_.flatMap" }
217+
218+ override DataFlow:: CallNode getACall ( ) { result = member ( "flatMap" ) .getACall ( ) }
219+
220+ override predicate propagatesFlow ( string input , string output , boolean preservesValue ) {
221+ (
222+ input = "Argument[0].ArrayElement" and
223+ output = "Argument[1].Parameter[0]"
224+ or
225+ input = "Argument[1].ReturnValue.WithoutArrayElement" and
226+ output = "ReturnValue.ArrayElement"
227+ or
228+ input = "Argument[1].ReturnValue.ArrayElement" and
229+ output = "ReturnValue.ArrayElement"
230+ ) and
231+ preservesValue = true
232+ }
233+ }
234+
235+ private class LodashFlatMapDeep extends DataFlow:: SummarizedCallable {
236+ LodashFlatMapDeep ( ) { this = "_.flatMapDeep" }
237+
238+ override DataFlow:: CallNode getACall ( ) {
239+ result = member ( [ "flatMapDeep" , "flatMapDepth" ] ) .getACall ( )
240+ }
241+
242+ override predicate propagatesFlow ( string input , string output , boolean preservesValue ) {
243+ (
244+ input = "Argument[0].ArrayElement" and
245+ output = "Argument[1].Parameter[0]"
246+ or
247+ input = "Argument[1].ReturnValue.WithoutArrayElement" and
248+ output = "ReturnValue.ArrayElement"
249+ or
250+ input = "Argument[1].ReturnValue.ArrayElementDeep" and
251+ output = "ReturnValue.ArrayElement"
252+ ) and
253+ preservesValue = true
254+ }
255+ }
256+
257+ private class LodashReduce extends DataFlow:: SummarizedCallable {
258+ LodashReduce ( ) { this = "_.reduce-like" }
259+
260+ override DataFlow:: CallNode getACall ( ) { result = member ( [ "reduce" , "reduceRight" ] ) .getACall ( ) }
261+
262+ override predicate propagatesFlow ( string input , string output , boolean preservesValue ) {
263+ (
264+ input = "Argument[0].ArrayElement" and
265+ output = "Argument[1].Parameter[1]"
266+ or
267+ input = [ "Argument[1].ReturnValue" , "Argument[2]" ] and
268+ output = [ "ReturnValue" , "Argument[1].Parameter[0]" ]
269+ ) and
270+ preservesValue = true
271+ }
272+ }
273+
274+ private class LoashSortBy extends DataFlow:: SummarizedCallable {
275+ LoashSortBy ( ) { this = "_.sortBy-like" }
276+
277+ override DataFlow:: CallNode getACall ( ) { result = member ( [ "sortBy" , "orderBy" ] ) .getACall ( ) }
278+
279+ override predicate propagatesFlow ( string input , string output , boolean preservesValue ) {
280+ input = "Argument[0].ArrayElement" and
281+ output = [ "Argument[1].Parameter[1]" , "ReturnValue.ArrayElement" ] and
282+ preservesValue = true
283+ }
284+ }
285+
286+ private class LodashMinMaxBy extends DataFlow:: SummarizedCallable {
287+ LodashMinMaxBy ( ) { this = "_.minBy / _.maxBy" }
288+
289+ override DataFlow:: CallNode getACall ( ) { result = member ( [ "minBy" , "maxBy" ] ) .getACall ( ) }
290+
291+ override predicate propagatesFlow ( string input , string output , boolean preservesValue ) {
292+ input = "Argument[0].ArrayElement" and
293+ output = [ "Argument[1].Parameter[1]" , "ReturnValue" ] and
294+ preservesValue = true
295+ }
296+ }
297+
298+ private class LodashPartition extends DataFlow:: SummarizedCallable {
299+ LodashPartition ( ) { this = "_.partition" }
300+
301+ override DataFlow:: CallNode getACall ( ) { result = member ( [ "partition" ] ) .getACall ( ) }
302+
303+ override predicate propagatesFlow ( string input , string output , boolean preservesValue ) {
304+ input = "Argument[0].ArrayElement" and
305+ output = [ "Argument[1].Parameter[1]" , "ReturnValue.ArrayElement.ArrayElement" ] and
306+ preservesValue = true
307+ }
308+ }
309+
310+ private class UnderscoreMapObject extends DataFlow:: SummarizedCallable {
311+ UnderscoreMapObject ( ) { this = "_.mapObject" }
312+
313+ override DataFlow:: CallNode getACall ( ) { result = member ( "mapObject" ) .getACall ( ) }
314+
315+ override predicate propagatesFlow ( string input , string output , boolean preservesValue ) {
316+ // Just collapse all properties with AnyMember. We could be more precise by generating a summary
317+ // for each property name, but for a rarely-used method like this it dosn't seem worth it.
318+ (
319+ input = "Argument[0].AnyMember" and
320+ output = "Argument[1].Parameter[1]"
321+ or
322+ input = "Argument[1].ReturnValue" and
323+ output = "ReturnValue.AnyMember"
324+ ) and
325+ preservesValue = true
326+ }
327+ }
328+
329+ private class LodashTap extends DataFlow:: SummarizedCallable {
330+ LodashTap ( ) { this = "_.tap" }
331+
332+ override DataFlow:: CallNode getACall ( ) { result = member ( "tap" ) .getACall ( ) }
333+
334+ override predicate propagatesFlow ( string input , string output , boolean preservesValue ) {
335+ input = "Argument[0]" and
336+ output = [ "Argument[1].Parameter[0]" , "ReturnValue" ] and
337+ preservesValue = true
338+ }
339+ }
171340}
172341
173342/**
0 commit comments