Skip to content

Commit 3d94ccf

Browse files
committed
JS: Support accessor-calls in object literals via local flow
1 parent b5be9d0 commit 3d94ccf

File tree

5 files changed

+41
-0
lines changed

5 files changed

+41
-0
lines changed

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,16 @@ class ObjectLiteralNode extends DataFlow::ValueNode, DataFlow::SourceNode {
546546
DataFlow::Node getASpreadProperty() {
547547
result = astNode.getAProperty().(SpreadProperty).getInit().(SpreadElement).getOperand().flow()
548548
}
549+
550+
/** Gets the property getter of the given name, installed on this object literal. */
551+
DataFlow::FunctionNode getPropertyGetter(string name) {
552+
result = astNode.getPropertyByName(name).(PropertyGetter).getInit().flow()
553+
}
554+
555+
/** Gets the property setter of the given name, installed on this object literal. */
556+
DataFlow::FunctionNode getPropertySetter(string name) {
557+
result = astNode.getPropertyByName(name).(PropertySetter).getInit().flow()
558+
}
549559
}
550560

551561
/**

javascript/ql/src/semmle/javascript/dataflow/internal/CallGraphs.qll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,5 +175,13 @@ module CallGraph {
175175
ref = cls.getAnInstanceReference().getAPropertyWrite(name) and
176176
result = cls.getInstanceMember(name, DataFlow::MemberKind::setter())
177177
)
178+
or
179+
exists(DataFlow::ObjectLiteralNode object, string name |
180+
ref = object.getAPropertyRead(name) and
181+
result = object.getPropertyGetter(name)
182+
or
183+
ref = object.getAPropertyWrite(name) and
184+
result = object.getPropertySetter(name)
185+
)
178186
}
179187
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ typeInferenceMismatch
7070
| getters-and-setters.js:6:20:6:27 | source() | getters-and-setters.js:13:18:13:20 | c.x |
7171
| getters-and-setters.js:27:15:27:22 | source() | getters-and-setters.js:23:18:23:18 | v |
7272
| getters-and-setters.js:47:23:47:30 | source() | getters-and-setters.js:45:14:45:16 | c.x |
73+
| getters-and-setters.js:60:20:60:27 | source() | getters-and-setters.js:66:10:66:14 | obj.x |
74+
| getters-and-setters.js:67:13:67:20 | source() | getters-and-setters.js:63:18:63:22 | value |
7375
| importedReactComponent.jsx:4:40:4:47 | source() | exportedReactComponent.jsx:2:10:2:19 | props.text |
7476
| indexOf.js:4:11:4:18 | source() | indexOf.js:9:10:9:10 | x |
7577
| json-stringify.js:2:16:2:23 | source() | json-stringify.js:5:8:5:29 | JSON.st ... source) |

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@
4545
| getters-and-setters.js:6:20:6:27 | source() | getters-and-setters.js:13:18:13:20 | c.x |
4646
| getters-and-setters.js:27:15:27:22 | source() | getters-and-setters.js:23:18:23:18 | v |
4747
| getters-and-setters.js:47:23:47:30 | source() | getters-and-setters.js:45:14:45:16 | c.x |
48+
| getters-and-setters.js:60:20:60:27 | source() | getters-and-setters.js:66:10:66:14 | obj.x |
49+
| getters-and-setters.js:67:13:67:20 | source() | getters-and-setters.js:63:18:63:22 | value |
4850
| indexOf.js:4:11:4:18 | source() | indexOf.js:9:10:9:10 | x |
4951
| indexOf.js:4:11:4:18 | source() | indexOf.js:13:10:13:10 | x |
5052
| nested-props.js:4:13:4:20 | source() | nested-props.js:5:10:5:14 | obj.x |

javascript/ql/test/library-tests/TaintTracking/getters-and-setters.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,22 @@ function testFlowThroughGetter() {
5353
sink(getX(new C(source()))); // NOT OK - but not flagged
5454
getX(null);
5555
}
56+
57+
function testFlowThroughObjectLiteralAccessors() {
58+
let obj = {
59+
get x() {
60+
return source();
61+
},
62+
set y(value) {
63+
sink(value); // NOT OK
64+
}
65+
};
66+
sink(obj.x); // NOT OK
67+
obj.y = source();
68+
69+
function indirection(c) {
70+
sink(c.x); // NOT OK - but not currently flagged
71+
}
72+
indirection(obj);
73+
indirection(null);
74+
}

0 commit comments

Comments
 (0)