add taint step through array-union, array-uniq, and uniq

This commit is contained in:
Erik Krogh Kristensen
2021-07-15 12:08:33 +02:00
parent 5ff7d208b7
commit 77f4d56cd9
6 changed files with 50 additions and 1 deletions

View File

@@ -5,4 +5,7 @@ lgtm,codescanning
[array.prototype.find](https://npmjs.com/package/array.prototype.find),
[array-find](https://npmjs.com/package/array-find),
[arrify](https://npmjs.com/package/arrify),
[array-ify](https://npmjs.com/package/array-ify)
[array-ify](https://npmjs.com/package/array-ify),
[array-union](https://npmjs.com/package/array-union),
[array-uniq](https://npmjs.com/package/array-uniq),
[uniq](https://npmjs.com/package/uniq)

View File

@@ -323,6 +323,8 @@ private import ArrayLibraries
* Classes and predicates modelling various libraries that work on arrays or array-like structures.
*/
private module ArrayLibraries {
private import DataFlow::PseudoProperties
/**
* Gets a call to `Array.from` or a polyfill implementing the same functionality.
*/
@@ -353,4 +355,38 @@ private module ArrayLibraries {
)
}
}
/**
* A call to a library that copies the elements of an array into another array.
* E.g. `array-union` that creates a union of multiple arrays, or `array-uniq` that creates an array with unique elements.
*/
DataFlow::CallNode arrayCopyCall(DataFlow::Node array) {
result = API::moduleImport(["array-union", "array-uniq", "uniq"]).getACall() and
array = result.getAnArgument()
}
/**
* A taint step for a library that copies the elements of an array into another array.
*/
private class ArrayCopyTaint extends TaintTracking::SharedTaintStep {
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
exists(DataFlow::CallNode call |
call = arrayCopyCall(pred) and
succ = call
)
}
}
/**
* A loadStoreStep for a library that copies the elements of an array into another array.
*/
private class ArrayCopyLoadStore extends DataFlow::SharedFlowStep {
override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
exists(DataFlow::CallNode call |
call = arrayCopyCall(pred) and
succ = call and
prop = arrayElement()
)
}
}
}

View File

@@ -10,6 +10,7 @@
| arrays.js:2:16:2:23 | "source" | arrays.js:71:10:71:10 | x |
| arrays.js:2:16:2:23 | "source" | arrays.js:74:8:74:29 | arr.fin ... llback) |
| arrays.js:2:16:2:23 | "source" | arrays.js:77:8:77:35 | arrayFi ... llback) |
| arrays.js:2:16:2:23 | "source" | arrays.js:81:10:81:10 | x |
| arrays.js:18:22:18:29 | "source" | arrays.js:18:50:18:50 | e |
| arrays.js:22:15:22:22 | "source" | arrays.js:23:8:23:17 | arr2.pop() |
| arrays.js:25:15:25:22 | "source" | arrays.js:26:8:26:17 | arr3.pop() |

View File

@@ -75,4 +75,9 @@
const arrayFind = require("array-find");
sink(arrayFind(arr, someCallback)); // NOT OK
const uniq = require("uniq");
for (const x of uniq(arr)) {
sink(x); // NOT OK
}
});

View File

@@ -14,6 +14,7 @@ typeInferenceMismatch
| array-mutation.js:39:17:39:24 | source() | array-mutation.js:40:8:40:8 | j |
| arrays.js:2:15:2:22 | source() | arrays.js:5:10:5:20 | arrify(foo) |
| arrays.js:2:15:2:22 | source() | arrays.js:8:10:8:22 | arrayIfy(foo) |
| arrays.js:2:15:2:22 | source() | arrays.js:11:10:11:28 | union(["bla"], foo) |
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:4:8:4:8 | x |
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:13:10:13:10 | x |
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:19:10:19:10 | x |

View File

@@ -6,4 +6,7 @@ function test() {
const arrayIfy = require("array-ify");
sink(arrayIfy(foo)); // NOT OK
const union = require("array-union");
sink(union(["bla"], foo)); // NOT OK
}