Skip to content

Commit 77f4d56

Browse files
committed
add taint step through array-union, array-uniq, and uniq
1 parent 5ff7d20 commit 77f4d56

File tree

6 files changed

+50
-1
lines changed

6 files changed

+50
-1
lines changed

javascript/change-notes/2021-07-15-array-libs.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,7 @@ lgtm,codescanning
55
[array.prototype.find](https://npmjs.com/package/array.prototype.find),
66
[array-find](https://npmjs.com/package/array-find),
77
[arrify](https://npmjs.com/package/arrify),
8-
[array-ify](https://npmjs.com/package/array-ify)
8+
[array-ify](https://npmjs.com/package/array-ify),
9+
[array-union](https://npmjs.com/package/array-union),
10+
[array-uniq](https://npmjs.com/package/array-uniq),
11+
[uniq](https://npmjs.com/package/uniq)

javascript/ql/src/semmle/javascript/Arrays.qll

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,8 @@ private import ArrayLibraries
323323
* Classes and predicates modelling various libraries that work on arrays or array-like structures.
324324
*/
325325
private module ArrayLibraries {
326+
private import DataFlow::PseudoProperties
327+
326328
/**
327329
* Gets a call to `Array.from` or a polyfill implementing the same functionality.
328330
*/
@@ -353,4 +355,38 @@ private module ArrayLibraries {
353355
)
354356
}
355357
}
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+
}
356392
}

javascript/ql/test/library-tests/Arrays/DataFlow.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
| arrays.js:2:16:2:23 | "source" | arrays.js:71:10:71:10 | x |
1111
| arrays.js:2:16:2:23 | "source" | arrays.js:74:8:74:29 | arr.fin ... llback) |
1212
| arrays.js:2:16:2:23 | "source" | arrays.js:77:8:77:35 | arrayFi ... llback) |
13+
| arrays.js:2:16:2:23 | "source" | arrays.js:81:10:81:10 | x |
1314
| arrays.js:18:22:18:29 | "source" | arrays.js:18:50:18:50 | e |
1415
| arrays.js:22:15:22:22 | "source" | arrays.js:23:8:23:17 | arr2.pop() |
1516
| arrays.js:25:15:25:22 | "source" | arrays.js:26:8:26:17 | arr3.pop() |

javascript/ql/test/library-tests/Arrays/arrays.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,9 @@
7575

7676
const arrayFind = require("array-find");
7777
sink(arrayFind(arr, someCallback)); // NOT OK
78+
79+
const uniq = require("uniq");
80+
for (const x of uniq(arr)) {
81+
sink(x); // NOT OK
82+
}
7883
});

javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ typeInferenceMismatch
1414
| array-mutation.js:39:17:39:24 | source() | array-mutation.js:40:8:40:8 | j |
1515
| arrays.js:2:15:2:22 | source() | arrays.js:5:10:5:20 | arrify(foo) |
1616
| arrays.js:2:15:2:22 | source() | arrays.js:8:10:8:22 | arrayIfy(foo) |
17+
| arrays.js:2:15:2:22 | source() | arrays.js:11:10:11:28 | union(["bla"], foo) |
1718
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:4:8:4:8 | x |
1819
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:13:10:13:10 | x |
1920
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:19:10:19:10 | x |

javascript/ql/test/library-tests/TaintTracking/arrays.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,7 @@ function test() {
66

77
const arrayIfy = require("array-ify");
88
sink(arrayIfy(foo)); // NOT OK
9+
10+
const union = require("array-union");
11+
sink(union(["bla"], foo)); // NOT OK
912
}

0 commit comments

Comments
 (0)