diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll b/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll index f571648294c2..ca1eb24f3b51 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll @@ -664,6 +664,10 @@ module Vue { or result = routeConfig().getMember("beforeEnter").getParameter([0, 1]).asSource() or + result = routeConfig().getMember("props").getParameter(0).asSource() + or + result = routeConfig().getMember("props").getAMember().getParameter(0).asSource() + or exists(Component c | result = c.getABoundFunction().getAFunctionValue().getReceiver().getAPropertyRead("$route") or diff --git a/javascript/ql/src/change-notes/2026-01-13-vue-props-callbacks.md b/javascript/ql/src/change-notes/2026-01-13-vue-props-callbacks.md new file mode 100644 index 000000000000..f84e193782d2 --- /dev/null +++ b/javascript/ql/src/change-notes/2026-01-13-vue-props-callbacks.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- +* The model of `vue-router` now properly detects taint sources in cases where + the `props` property is a callback. diff --git a/javascript/ql/test/library-tests/frameworks/Vue/router.js b/javascript/ql/test/library-tests/frameworks/Vue/router.js index acbbefecc019..65dc4d13e99e 100644 --- a/javascript/ql/test/library-tests/frameworks/Vue/router.js +++ b/javascript/ql/test/library-tests/frameworks/Vue/router.js @@ -16,8 +16,17 @@ export const router = new Router({ from.query.x; } } - ] - } + ], + props: route => ({ + x: route.query.x + }), + }, + { + props: { + x: route => route.query.x, + y: route => route.query.y + }, + }, ], scrollBehavior(to, from, savedPosition) { to.query.x; @@ -34,4 +43,3 @@ router.afterEach((to, from) => { to.query.x; from.query.x; }); - diff --git a/javascript/ql/test/library-tests/frameworks/Vue/tests.expected b/javascript/ql/test/library-tests/frameworks/Vue/tests.expected index 4fe66404c782..633a8f9924db 100644 --- a/javascript/ql/test/library-tests/frameworks/Vue/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Vue/tests.expected @@ -182,12 +182,15 @@ remoteFlowSource | router.js:9:17:9:26 | from.query | | router.js:15:25:15:32 | to.query | | router.js:16:25:16:34 | from.query | -| router.js:23:9:23:16 | to.query | -| router.js:24:9:24:18 | from.query | -| router.js:29:5:29:12 | to.query | -| router.js:30:5:30:14 | from.query | -| router.js:34:5:34:12 | to.query | -| router.js:35:5:35:14 | from.query | +| router.js:21:20:21:30 | route.query | +| router.js:26:29:26:39 | route.query | +| router.js:27:29:27:39 | route.query | +| router.js:32:9:32:16 | to.query | +| router.js:33:9:33:18 | from.query | +| router.js:38:5:38:12 | to.query | +| router.js:39:5:39:14 | from.query | +| router.js:43:5:43:12 | to.query | +| router.js:44:5:44:14 | from.query | parseErrors attribute | compont-with-route.vue:2:8:2:21 | v-html=dataA | v-html | @@ -227,12 +230,15 @@ threatModelSource | router.js:9:17:9:26 | from.query | remote | | router.js:15:25:15:32 | to.query | remote | | router.js:16:25:16:34 | from.query | remote | -| router.js:23:9:23:16 | to.query | remote | -| router.js:24:9:24:18 | from.query | remote | -| router.js:29:5:29:12 | to.query | remote | -| router.js:30:5:30:14 | from.query | remote | -| router.js:34:5:34:12 | to.query | remote | -| router.js:35:5:35:14 | from.query | remote | +| router.js:21:20:21:30 | route.query | remote | +| router.js:26:29:26:39 | route.query | remote | +| router.js:27:29:27:39 | route.query | remote | +| router.js:32:9:32:16 | to.query | remote | +| router.js:33:9:33:18 | from.query | remote | +| router.js:38:5:38:12 | to.query | remote | +| router.js:39:5:39:14 | from.query | remote | +| router.js:43:5:43:12 | to.query | remote | +| router.js:44:5:44:14 | from.query | remote | | single-component-file-1.vue:7:45:7:54 | this.input | view-component-input | | single-file-component-3-script.js:5:42:5:51 | this.input | view-component-input | | single-file-component-4.vue:21:14:21:23 | this.input | view-component-input |