diff --git a/javascript/ql/lib/change-notes/2024-11-12-immutable-array-operations.md b/javascript/ql/lib/change-notes/2024-11-12-immutable-array-operations.md new file mode 100644 index 000000000000..20c16d88c6e0 --- /dev/null +++ b/javascript/ql/lib/change-notes/2024-11-12-immutable-array-operations.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- +* Added taint-steps for `Array.prototype.toReversed`. +* Added taint-steps for `Array.prototype.toSorted`. diff --git a/javascript/ql/lib/semmle/javascript/Arrays.qll b/javascript/ql/lib/semmle/javascript/Arrays.qll index ebff3d97a981..d4360072aa28 100644 --- a/javascript/ql/lib/semmle/javascript/Arrays.qll +++ b/javascript/ql/lib/semmle/javascript/Arrays.qll @@ -458,4 +458,18 @@ private module ArrayLibraries { ) } } + + /** + * A taint propagating data flow edge arising from array transformation operations + * that return a new array instead of modifying the original array in place. + */ + private class ImmutableArrayTransformStep extends TaintTracking::SharedTaintStep { + override predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) { + exists(DataFlow::MethodCallNode call | + call.getMethodName() in ["toSorted", "toReversed"] and + pred = call.getReceiver() and + succ = call + ) + } + } } diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index b1f3e7b26bda..ba15575eb9cd 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -234,6 +234,10 @@ typeInferenceMismatch | tst.js:2:13:2:20 | source() | tst.js:51:10:51:31 | seriali ... ript(x) | | tst.js:2:13:2:20 | source() | tst.js:54:14:54:19 | unsafe | | tst.js:2:13:2:20 | source() | tst.js:61:10:61:20 | x.reverse() | +| tst.js:2:13:2:20 | source() | tst.js:63:10:63:21 | x.toSorted() | +| tst.js:2:13:2:20 | source() | tst.js:65:10:65:16 | xSorted | +| tst.js:2:13:2:20 | source() | tst.js:67:10:67:23 | x.toReversed() | +| tst.js:2:13:2:20 | source() | tst.js:69:10:69:18 | xReversed | | xml.js:5:18:5:25 | source() | xml.js:8:14:8:17 | text | | xml.js:12:17:12:24 | source() | xml.js:13:14:13:19 | result | | xml.js:23:18:23:25 | source() | xml.js:20:14:20:17 | attr | diff --git a/javascript/ql/test/library-tests/TaintTracking/tst.js b/javascript/ql/test/library-tests/TaintTracking/tst.js index 475e6fdbff0e..3af935687a06 100644 --- a/javascript/ql/test/library-tests/TaintTracking/tst.js +++ b/javascript/ql/test/library-tests/TaintTracking/tst.js @@ -59,4 +59,12 @@ function test() { tagged`foo ${"safe"} bar ${x} baz`; sink(x.reverse()); // NOT OK + + sink(x.toSorted()) // NOT OK + const xSorted = x.toSorted(); + sink(xSorted) // NOT OK + + sink(x.toReversed()) // NOT OK + const xReversed = x.toReversed(); + sink(xReversed) // NOT OK }