Skip to content

Commit bd3f6d1

Browse files
committed
JS: Add o[o.length] = y taint step
1 parent 51f4892 commit bd3f6d1

File tree

3 files changed

+17
-8
lines changed

3 files changed

+17
-8
lines changed

javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -584,22 +584,26 @@ module TaintTracking {
584584

585585
/**
586586
* A taint propagating data flow edge for assignments of the form `o[k] = v`, where
587-
* `k` is not a constant and `o` refers to some object literal; in this case, we consider
588-
* taint to flow from `v` to that object literal.
587+
* one of the following holds:
589588
*
590-
* The rationale for this heuristic is that if properties of `o` are accessed by
591-
* computed (that is, non-constant) names, then `o` is most likely being treated as
592-
* a map, not as a real object. In this case, it makes sense to consider the entire
593-
* map to be tainted as soon as one of its entries is.
589+
* - `k` is not a constant and `o` refers to some object literal. The rationale
590+
* here is that `o` is most likely being used like a dictionary object.
591+
*
592+
* - `k` refers to `o.length`, that is, the assignment is of form `o[o.length] = v`.
593+
* In this case, the assignment behaves like `o.push(v)`.
594594
*/
595-
private class DictionaryTaintStep extends SharedTaintStep {
595+
private class ComputedPropWriteTaintStep extends SharedTaintStep {
596596
override predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) {
597-
exists(AssignExpr assgn, IndexExpr idx, DataFlow::ObjectLiteralNode obj |
597+
exists(AssignExpr assgn, IndexExpr idx, DataFlow::SourceNode obj |
598598
assgn.getTarget() = idx and
599599
obj.flowsToExpr(idx.getBase()) and
600600
not exists(idx.getPropertyName()) and
601601
pred = DataFlow::valueNode(assgn.getRhs()) and
602602
succ = obj
603+
|
604+
obj instanceof DataFlow::ObjectLiteralNode
605+
or
606+
obj.getAPropertyRead("length").flowsToExpr(idx.getPropertyNameExpr())
603607
)
604608
}
605609
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ typeInferenceMismatch
1111
| array-mutation.js:27:16:27:23 | source() | array-mutation.js:28:8:28:8 | g |
1212
| array-mutation.js:31:33:31:40 | source() | array-mutation.js:32:8:32:8 | h |
1313
| array-mutation.js:35:36:35:43 | source() | array-mutation.js:36:8:36:8 | i |
14+
| array-mutation.js:39:17:39:24 | source() | array-mutation.js:40:8:40:8 | j |
1415
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:4:8:4:8 | x |
1516
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:13:10:13:10 | x |
1617
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:19:10:19:10 | x |

javascript/ql/test/library-tests/TaintTracking/array-mutation.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,8 @@ function test(x, y) {
3434
let i = [];
3535
Array.prototype.unshift.apply(i, source());
3636
sink(i); // NOT OK
37+
38+
let j = [];
39+
j[j.length] = source();
40+
sink(j); // NOT OK
3741
}

0 commit comments

Comments
 (0)