Skip to content

Commit dc15554

Browse files
authored
Move Vue flow models into QL
1 parent dfb0487 commit dc15554

5 files changed

Lines changed: 64 additions & 15 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Added flow models for Vue's `ref`, `shallowRef`, `toRef`, `reactive`, and `computed` Composition API helpers.

javascript/ql/lib/ext/vue.model.yml

Lines changed: 0 additions & 15 deletions
This file was deleted.

javascript/ql/lib/semmle/javascript/frameworks/Vue.qll

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,42 @@ module Vue {
3535
result = any(GlobalVueEntryPoint e).getANode()
3636
}
3737

38+
/** Models data flow through Vue Composition API helpers. */
39+
private class VueCompositionApiSummary extends DataFlow::SummarizedCallable::Range {
40+
string name;
41+
42+
VueCompositionApiSummary() {
43+
name = ["ref", "shallowRef", "toRef", "reactive", "computed"] and
44+
this = "vue." + name
45+
}
46+
47+
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
48+
name = ["ref", "shallowRef"] and
49+
input = "Argument[0]" and
50+
output = "ReturnValue.Member[value]" and
51+
preservesValue = true
52+
or
53+
name = "toRef" and
54+
input = "Argument[0]" and
55+
output = "ReturnValue.Member[value]" and
56+
preservesValue = false
57+
or
58+
name = "reactive" and
59+
input = "Argument[0]" and
60+
output = "ReturnValue" and
61+
preservesValue = false
62+
or
63+
name = "computed" and
64+
input = "Argument[0].ReturnValue" and
65+
output = "ReturnValue.Member[value]" and
66+
preservesValue = true
67+
}
68+
69+
override DataFlow::InvokeNode getACall() {
70+
result = API::moduleImport("vue").getMember(name).getACall()
71+
}
72+
}
73+
3874
/**
3975
* Gets a reference to the 'Vue' object.
4076
*/

javascript/ql/test/library-tests/frameworks/Vue/tests.ql

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,24 @@
11
import javascript
22
import semmle.javascript.security.dataflow.DomBasedXssCustomizations
33

4+
module TestConfig implements DataFlow::ConfigSig {
5+
predicate isSource(DataFlow::Node source) {
6+
source.(DataFlow::CallNode).getCalleeName() = "source"
7+
}
8+
9+
predicate isSink(DataFlow::Node sink) {
10+
sink = any(DataFlow::CallNode call | call.getCalleeName() = "sink").getAnArgument()
11+
}
12+
}
13+
14+
module TestDataFlow = DataFlow::Global<TestConfig>;
15+
16+
module TestTaintFlow = TaintTracking::Global<TestConfig>;
17+
18+
query predicate compositionApiDataFlow = TestDataFlow::flow/2;
19+
20+
query predicate compositionApiTaintFlow = TestTaintFlow::flow/2;
21+
422
query predicate component_getAPropertyValue(Vue::Component c, string name, DataFlow::Node prop) {
523
c.getAPropertyValue(name) = prop
624
}

javascript/ql/test/library-tests/frameworks/Vue/tst.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,9 @@ let subclass2 = base.extend({
115115
fromSubclass2: 100
116116
}
117117
});
118+
119+
sink(Vue.ref(source("ref")).value);
120+
sink(Vue.shallowRef(source("shallowRef")).value);
121+
sink(Vue.toRef(source("toRef")).value);
122+
sink(Vue.reactive(source("reactive")));
123+
sink(Vue.computed(() => source("computed")).value);

0 commit comments

Comments
 (0)