From 7712ca368aae8c3a604f348d19c4e6c9a7a769b7 Mon Sep 17 00:00:00 2001
From: Napalys
Date: Thu, 13 Mar 2025 08:20:05 +0100
Subject: [PATCH 01/10] Added `useQuery` `tanstack-vue` test case
---
.../Xss.expected | 3 +++
.../DomBasedXssWithResponseThreat/test.vue | 24 +++++++++++++++++++
2 files changed, 27 insertions(+)
create mode 100644 javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/test.vue
diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected
index 313febe21946..ccbea1a798b9 100644
--- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected
+++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected
@@ -112,3 +112,6 @@ nodes
| testReactRelay.tsx:136:16:136:39 | readFra ... y, key) | semmle.label | readFra ... y, key) |
| testReactRelay.tsx:137:50:137:53 | data | semmle.label | data |
subpaths
+testFailures
+| test.vue:10:87:10:97 | // $ Source | Missing result: Source |
+| test.vue:22:31:22:53 | | Missing result: Alert[js/xss] |
diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/test.vue b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/test.vue
new file mode 100644
index 000000000000..0db6637a8cb5
--- /dev/null
+++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/test.vue
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
From 0c0158899e45b4d50b009befe1f42e2b66b6ab8e Mon Sep 17 00:00:00 2001
From: Napalys
Date: Thu, 13 Mar 2025 08:21:10 +0100
Subject: [PATCH 02/10] Added `tanstack-vue` `useQuery` modeling
---
javascript/ql/lib/ext/tanstack.model.yml | 1 +
.../Xss.expected | 21 ++++++++++++++++---
2 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/javascript/ql/lib/ext/tanstack.model.yml b/javascript/ql/lib/ext/tanstack.model.yml
index 19b57eae6124..9655bca5dc0d 100644
--- a/javascript/ql/lib/ext/tanstack.model.yml
+++ b/javascript/ql/lib/ext/tanstack.model.yml
@@ -5,3 +5,4 @@ extensions:
data:
- ["@tanstack/angular-query-experimental", "Member[injectQuery]", "Argument[0].ReturnValue.Member[queryFn].ReturnValue", "ReturnValue.Member[data].Awaited", "taint"]
- ["@tanstack/angular-query", "Member[injectQuery]", "Argument[0].ReturnValue.Member[queryFn].ReturnValue", "ReturnValue.Member[data].Awaited", "taint"]
+ - ["@tanstack/vue-query", "Member[useQuery]", "Argument[0].Member[queryFn].ReturnValue.Awaited", "ReturnValue.Member[data]", "taint"]
diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected
index ccbea1a798b9..fb3ceceb0550 100644
--- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected
+++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected
@@ -2,6 +2,7 @@
| test.jsx:27:29:27:32 | data | test.jsx:5:28:5:63 | fetch(" ... ntent") | test.jsx:27:29:27:32 | data | Cross-site scripting vulnerability due to $@. | test.jsx:5:28:5:63 | fetch(" ... ntent") | user-provided value |
| test.ts:21:57:21:76 | response.description | test.ts:8:9:8:79 | this.#h ... query') | test.ts:21:57:21:76 | response.description | Cross-site scripting vulnerability due to $@. | test.ts:8:9:8:79 | this.#h ... query') | user-provided value |
| test.ts:24:36:24:90 | `${ ... o}
` | test.ts:8:9:8:79 | this.#h ... query') | test.ts:24:36:24:90 | `${ ... o}` | Cross-site scripting vulnerability due to $@. | test.ts:8:9:8:79 | this.#h ... query') | user-provided value |
+| test.vue:22:10:22:22 | v-html=data | test.vue:10:32:10:84 | fetch(" ... sts/1") | test.vue:22:10:22:22 | v-html=data | Cross-site scripting vulnerability due to $@. | test.vue:10:32:10:84 | fetch(" ... sts/1") | user-provided value |
| testReactRelay.tsx:7:43:7:58 | commentData.text | testReactRelay.tsx:5:23:5:52 | useFrag ... entRef) | testReactRelay.tsx:7:43:7:58 | commentData.text | Cross-site scripting vulnerability due to $@. | testReactRelay.tsx:5:23:5:52 | useFrag ... entRef) | user-provided value |
| testReactRelay.tsx:18:48:18:68 | data.co ... 0].text | testReactRelay.tsx:17:16:17:42 | useLazy ... ry, {}) | testReactRelay.tsx:18:48:18:68 | data.co ... 0].text | Cross-site scripting vulnerability due to $@. | testReactRelay.tsx:17:16:17:42 | useLazy ... ry, {}) | user-provided value |
| testReactRelay.tsx:28:17:28:67 | usePrel ... r?.name | testReactRelay.tsx:28:17:28:56 | usePrel ... erence) | testReactRelay.tsx:28:17:28:67 | usePrel ... r?.name | Cross-site scripting vulnerability due to $@. | testReactRelay.tsx:28:17:28:56 | usePrel ... erence) | user-provided value |
@@ -31,6 +32,14 @@ edges
| test.ts:24:43:24:55 | response.name | test.ts:24:36:24:90 | `${ ... o}` | provenance | |
| test.ts:24:67:24:74 | response | test.ts:24:67:24:84 | response.owner.bio | provenance | |
| test.ts:24:67:24:84 | response.owner.bio | test.ts:24:36:24:90 | `${ ... o}` | provenance | |
+| test.vue:7:11:13:6 | data | test.vue:15:21:15:24 | data | provenance | |
+| test.vue:7:45:7:48 | data | test.vue:7:11:13:6 | data | provenance | |
+| test.vue:10:15:10:84 | response | test.vue:11:16:11:23 | response | provenance | |
+| test.vue:10:26:10:84 | await f ... sts/1") | test.vue:10:15:10:84 | response | provenance | |
+| test.vue:10:32:10:84 | fetch(" ... sts/1") | test.vue:10:26:10:84 | await f ... sts/1") | provenance | |
+| test.vue:11:16:11:23 | response | test.vue:11:16:11:30 | response.json() | provenance | |
+| test.vue:11:16:11:30 | response.json() | test.vue:7:45:7:48 | data | provenance | |
+| test.vue:15:21:15:24 | data | test.vue:22:10:22:22 | v-html=data | provenance | |
| testReactRelay.tsx:5:9:5:52 | commentData | testReactRelay.tsx:7:43:7:53 | commentData | provenance | |
| testReactRelay.tsx:5:23:5:52 | useFrag ... entRef) | testReactRelay.tsx:5:9:5:52 | commentData | provenance | |
| testReactRelay.tsx:7:43:7:53 | commentData | testReactRelay.tsx:7:43:7:58 | commentData.text | provenance | |
@@ -76,6 +85,15 @@ nodes
| test.ts:24:43:24:55 | response.name | semmle.label | response.name |
| test.ts:24:67:24:74 | response | semmle.label | response |
| test.ts:24:67:24:84 | response.owner.bio | semmle.label | response.owner.bio |
+| test.vue:7:11:13:6 | data | semmle.label | data |
+| test.vue:7:45:7:48 | data | semmle.label | data |
+| test.vue:10:15:10:84 | response | semmle.label | response |
+| test.vue:10:26:10:84 | await f ... sts/1") | semmle.label | await f ... sts/1") |
+| test.vue:10:32:10:84 | fetch(" ... sts/1") | semmle.label | fetch(" ... sts/1") |
+| test.vue:11:16:11:23 | response | semmle.label | response |
+| test.vue:11:16:11:30 | response.json() | semmle.label | response.json() |
+| test.vue:15:21:15:24 | data | semmle.label | data |
+| test.vue:22:10:22:22 | v-html=data | semmle.label | v-html=data |
| testReactRelay.tsx:5:9:5:52 | commentData | semmle.label | commentData |
| testReactRelay.tsx:5:23:5:52 | useFrag ... entRef) | semmle.label | useFrag ... entRef) |
| testReactRelay.tsx:7:43:7:53 | commentData | semmle.label | commentData |
@@ -112,6 +130,3 @@ nodes
| testReactRelay.tsx:136:16:136:39 | readFra ... y, key) | semmle.label | readFra ... y, key) |
| testReactRelay.tsx:137:50:137:53 | data | semmle.label | data |
subpaths
-testFailures
-| test.vue:10:87:10:97 | // $ Source | Missing result: Source |
-| test.vue:22:31:22:53 | | Missing result: Alert[js/xss] |
From 4917d64ce71223e6708a53015f85bc09f6651de8 Mon Sep 17 00:00:00 2001
From: Napalys
Date: Thu, 13 Mar 2025 11:39:35 +0100
Subject: [PATCH 03/10] Added test cases for `tanstack-vue` `useQueries`.
---
.../Xss.expected | 3 ++
.../testUseQueries.vue | 27 ++++++++++++++
.../testUseQueries2.vue | 37 +++++++++++++++++++
3 files changed, 67 insertions(+)
create mode 100644 javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/testUseQueries.vue
create mode 100644 javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/testUseQueries2.vue
diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected
index fb3ceceb0550..a6a305505f06 100644
--- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected
+++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected
@@ -130,3 +130,6 @@ nodes
| testReactRelay.tsx:136:16:136:39 | readFra ... y, key) | semmle.label | readFra ... y, key) |
| testReactRelay.tsx:137:50:137:53 | data | semmle.label | data |
subpaths
+testFailures
+| testUseQueries2.vue:6:66:6:76 | // $ Source | Missing result: Source |
+| testUseQueries2.vue:35:32:35:46 | | Missing result: Alert |
diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/testUseQueries.vue b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/testUseQueries.vue
new file mode 100644
index 000000000000..c02c0a79023f
--- /dev/null
+++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/testUseQueries.vue
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/testUseQueries2.vue b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/testUseQueries2.vue
new file mode 100644
index 000000000000..5ed896cf99d1
--- /dev/null
+++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/testUseQueries2.vue
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
From 6c9aa0e872ecf458544458fb2b95177f9c51ccb1 Mon Sep 17 00:00:00 2001
From: Napalys
Date: Thu, 13 Mar 2025 11:40:44 +0100
Subject: [PATCH 04/10] Added modeling of `tanstack-vue` `useQueries`.
---
javascript/ql/lib/ext/tanstack.model.yml | 1 +
.../Xss.expected | 23 ++++++++++++++++---
.../testUseQueries2.vue | 7 +++++-
3 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/javascript/ql/lib/ext/tanstack.model.yml b/javascript/ql/lib/ext/tanstack.model.yml
index 9655bca5dc0d..f42a9bd17198 100644
--- a/javascript/ql/lib/ext/tanstack.model.yml
+++ b/javascript/ql/lib/ext/tanstack.model.yml
@@ -6,3 +6,4 @@ extensions:
- ["@tanstack/angular-query-experimental", "Member[injectQuery]", "Argument[0].ReturnValue.Member[queryFn].ReturnValue", "ReturnValue.Member[data].Awaited", "taint"]
- ["@tanstack/angular-query", "Member[injectQuery]", "Argument[0].ReturnValue.Member[queryFn].ReturnValue", "ReturnValue.Member[data].Awaited", "taint"]
- ["@tanstack/vue-query", "Member[useQuery]", "Argument[0].Member[queryFn].ReturnValue.Awaited", "ReturnValue.Member[data]", "taint"]
+ - ["@tanstack/vue-query", "Member[useQueries]", "Argument[0].Member[queries].ArrayElement.Member[queryFn].ReturnValue.Awaited", "ReturnValue.AnyMember.Member[data]", "taint"]
diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected
index a6a305505f06..8d1c98ab4a9d 100644
--- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected
+++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected
@@ -13,6 +13,7 @@
| testReactRelay.tsx:113:48:113:58 | fragmentRef | testReactRelay.tsx:100:14:100:16 | res | testReactRelay.tsx:113:48:113:58 | fragmentRef | Cross-site scripting vulnerability due to $@. | testReactRelay.tsx:100:14:100:16 | res | user-provided value |
| testReactRelay.tsx:127:35:127:43 | data.user | testReactRelay.tsx:124:12:124:15 | data | testReactRelay.tsx:127:35:127:43 | data.user | Cross-site scripting vulnerability due to $@. | testReactRelay.tsx:124:12:124:15 | data | user-provided value |
| testReactRelay.tsx:137:50:137:53 | data | testReactRelay.tsx:136:16:136:39 | readFra ... y, key) | testReactRelay.tsx:137:50:137:53 | data | Cross-site scripting vulnerability due to $@. | testReactRelay.tsx:136:16:136:39 | readFra ... y, key) | user-provided value |
+| testUseQueries2.vue:40:10:40:23 | v-html=data3 | testUseQueries2.vue:6:28:6:63 | fetch(" ... ntent") | testUseQueries2.vue:40:10:40:23 | v-html=data3 | Cross-site scripting vulnerability due to $@. | testUseQueries2.vue:6:28:6:63 | fetch(" ... ntent") | user-provided value |
edges
| test.jsx:5:11:5:63 | response | test.jsx:6:24:6:31 | response | provenance | |
| test.jsx:5:22:5:63 | await f ... ntent") | test.jsx:5:11:5:63 | response | provenance | |
@@ -65,6 +66,15 @@ edges
| testReactRelay.tsx:127:35:127:38 | data | testReactRelay.tsx:127:35:127:43 | data.user | provenance | |
| testReactRelay.tsx:136:9:136:39 | data | testReactRelay.tsx:137:50:137:53 | data | provenance | |
| testReactRelay.tsx:136:16:136:39 | readFra ... y, key) | testReactRelay.tsx:136:9:136:39 | data | provenance | |
+| testUseQueries2.vue:6:11:6:63 | response | testUseQueries2.vue:7:24:7:31 | response | provenance | |
+| testUseQueries2.vue:6:22:6:63 | await f ... ntent") | testUseQueries2.vue:6:11:6:63 | response | provenance | |
+| testUseQueries2.vue:6:28:6:63 | fetch(" ... ntent") | testUseQueries2.vue:6:22:6:63 | await f ... ntent") | provenance | |
+| testUseQueries2.vue:7:11:7:38 | data | testUseQueries2.vue:8:12:8:15 | data | provenance | |
+| testUseQueries2.vue:7:18:7:38 | await r ... .json() | testUseQueries2.vue:7:11:7:38 | data | provenance | |
+| testUseQueries2.vue:7:24:7:31 | response | testUseQueries2.vue:7:24:7:38 | response.json() | provenance | |
+| testUseQueries2.vue:7:24:7:38 | response.json() | testUseQueries2.vue:7:18:7:38 | await r ... .json() | provenance | |
+| testUseQueries2.vue:8:12:8:15 | data | testUseQueries2.vue:33:22:33:36 | results[0].data | provenance | |
+| testUseQueries2.vue:33:22:33:36 | results[0].data | testUseQueries2.vue:40:10:40:23 | v-html=data3 | provenance | |
nodes
| test.jsx:5:11:5:63 | response | semmle.label | response |
| test.jsx:5:22:5:63 | await f ... ntent") | semmle.label | await f ... ntent") |
@@ -129,7 +139,14 @@ nodes
| testReactRelay.tsx:136:9:136:39 | data | semmle.label | data |
| testReactRelay.tsx:136:16:136:39 | readFra ... y, key) | semmle.label | readFra ... y, key) |
| testReactRelay.tsx:137:50:137:53 | data | semmle.label | data |
+| testUseQueries2.vue:6:11:6:63 | response | semmle.label | response |
+| testUseQueries2.vue:6:22:6:63 | await f ... ntent") | semmle.label | await f ... ntent") |
+| testUseQueries2.vue:6:28:6:63 | fetch(" ... ntent") | semmle.label | fetch(" ... ntent") |
+| testUseQueries2.vue:7:11:7:38 | data | semmle.label | data |
+| testUseQueries2.vue:7:18:7:38 | await r ... .json() | semmle.label | await r ... .json() |
+| testUseQueries2.vue:7:24:7:31 | response | semmle.label | response |
+| testUseQueries2.vue:7:24:7:38 | response.json() | semmle.label | response.json() |
+| testUseQueries2.vue:8:12:8:15 | data | semmle.label | data |
+| testUseQueries2.vue:33:22:33:36 | results[0].data | semmle.label | results[0].data |
+| testUseQueries2.vue:40:10:40:23 | v-html=data3 | semmle.label | v-html=data3 |
subpaths
-testFailures
-| testUseQueries2.vue:6:66:6:76 | // $ Source | Missing result: Source |
-| testUseQueries2.vue:35:32:35:46 | | Missing result: Alert |
diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/testUseQueries2.vue b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/testUseQueries2.vue
index 5ed896cf99d1..571d245b2335 100644
--- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/testUseQueries2.vue
+++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/testUseQueries2.vue
@@ -8,6 +8,11 @@ const fetchContent = async () => {
return data;
};
+async function fetchPost() {
+ const response = await fetch("${id}"); // $ MISSING: Source
+ return response.json();
+}
+
export default {
data() {
const results = useQueries({
@@ -19,7 +24,7 @@ export default {
},
{
queryKey: ["post", 2],
- queryFn: () => fetchPost(2),
+ queryFn: () => fetchPost(),
staleTime: Infinity,
},
],
From 03330ef24d2920ed73adbbea9d8ff1a22c6c77d3 Mon Sep 17 00:00:00 2001
From: Napalys
Date: Thu, 13 Mar 2025 11:59:11 +0100
Subject: [PATCH 05/10] Added test cases for `tanstack-react` `useQueries`.
---
.../testReactUseQueries.jsx | 42 +++++++++++++++++++
1 file changed, 42 insertions(+)
create mode 100644 javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/testReactUseQueries.jsx
diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/testReactUseQueries.jsx b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/testReactUseQueries.jsx
new file mode 100644
index 000000000000..cd8fccad0ca1
--- /dev/null
+++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/testReactUseQueries.jsx
@@ -0,0 +1,42 @@
+import { useQueries } from '@tanstack/react-query';
+
+const fetchRepoData = async () => {
+ const response = await fetch('https://example.com'); // $ MISSING: Source
+ return response.json();
+};
+
+async function fetchPost() {
+ const response = await fetch("www.example.com"); // $ MISSING: Source
+ return response.json();
+}
+
+export default function UseQueriesComponent() {
+ const results = useQueries({
+ queries: [
+ {
+ queryKey: ['repoData'],
+ queryFn: fetchRepoData,
+ },
+ {
+ queryKey: ['repoData'],
+ queryFn: () => fetchPost,
+ },
+ ],
+ });
+
+ const repoQuery = results[0];
+
+ if (repoQuery.isLoading) return Loading...
;
+ if (repoQuery.isError) return Error: {repoQuery.error.message}
;
+
+ return (
+
+
Content with Dangerous HTML
+
+
+);
+}
From 3640e5e4252dfe874eaa48f41896bcecc036b4ef Mon Sep 17 00:00:00 2001
From: Napalys
Date: Thu, 13 Mar 2025 12:03:01 +0100
Subject: [PATCH 06/10] Added model for `tanstack-react` `useQueries`
---
javascript/ql/lib/ext/tanstack.model.yml | 1 +
.../DomBasedXssWithResponseThreat/Xss.expected | 12 ++++++++++++
.../testReactUseQueries.jsx | 4 ++--
3 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/javascript/ql/lib/ext/tanstack.model.yml b/javascript/ql/lib/ext/tanstack.model.yml
index f42a9bd17198..b9498a6af326 100644
--- a/javascript/ql/lib/ext/tanstack.model.yml
+++ b/javascript/ql/lib/ext/tanstack.model.yml
@@ -7,3 +7,4 @@ extensions:
- ["@tanstack/angular-query", "Member[injectQuery]", "Argument[0].ReturnValue.Member[queryFn].ReturnValue", "ReturnValue.Member[data].Awaited", "taint"]
- ["@tanstack/vue-query", "Member[useQuery]", "Argument[0].Member[queryFn].ReturnValue.Awaited", "ReturnValue.Member[data]", "taint"]
- ["@tanstack/vue-query", "Member[useQueries]", "Argument[0].Member[queries].ArrayElement.Member[queryFn].ReturnValue.Awaited", "ReturnValue.AnyMember.Member[data]", "taint"]
+ - ["@tanstack/react-query", "Member[useQueries]", "Argument[0].Member[queries].ArrayElement.Member[queryFn].ReturnValue.Awaited", "ReturnValue.AnyMember.Member[data]", "taint"]
diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected
index 8d1c98ab4a9d..7c5081156a87 100644
--- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected
+++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected
@@ -13,6 +13,7 @@
| testReactRelay.tsx:113:48:113:58 | fragmentRef | testReactRelay.tsx:100:14:100:16 | res | testReactRelay.tsx:113:48:113:58 | fragmentRef | Cross-site scripting vulnerability due to $@. | testReactRelay.tsx:100:14:100:16 | res | user-provided value |
| testReactRelay.tsx:127:35:127:43 | data.user | testReactRelay.tsx:124:12:124:15 | data | testReactRelay.tsx:127:35:127:43 | data.user | Cross-site scripting vulnerability due to $@. | testReactRelay.tsx:124:12:124:15 | data | user-provided value |
| testReactRelay.tsx:137:50:137:53 | data | testReactRelay.tsx:136:16:136:39 | readFra ... y, key) | testReactRelay.tsx:137:50:137:53 | data | Cross-site scripting vulnerability due to $@. | testReactRelay.tsx:136:16:136:39 | readFra ... y, key) | user-provided value |
+| testReactUseQueries.jsx:37:25:37:38 | repoQuery.data | testReactUseQueries.jsx:4:26:4:53 | fetch(' ... e.com') | testReactUseQueries.jsx:37:25:37:38 | repoQuery.data | Cross-site scripting vulnerability due to $@. | testReactUseQueries.jsx:4:26:4:53 | fetch(' ... e.com') | user-provided value |
| testUseQueries2.vue:40:10:40:23 | v-html=data3 | testUseQueries2.vue:6:28:6:63 | fetch(" ... ntent") | testUseQueries2.vue:40:10:40:23 | v-html=data3 | Cross-site scripting vulnerability due to $@. | testUseQueries2.vue:6:28:6:63 | fetch(" ... ntent") | user-provided value |
edges
| test.jsx:5:11:5:63 | response | test.jsx:6:24:6:31 | response | provenance | |
@@ -66,6 +67,11 @@ edges
| testReactRelay.tsx:127:35:127:38 | data | testReactRelay.tsx:127:35:127:43 | data.user | provenance | |
| testReactRelay.tsx:136:9:136:39 | data | testReactRelay.tsx:137:50:137:53 | data | provenance | |
| testReactRelay.tsx:136:16:136:39 | readFra ... y, key) | testReactRelay.tsx:136:9:136:39 | data | provenance | |
+| testReactUseQueries.jsx:4:9:4:53 | response | testReactUseQueries.jsx:5:10:5:17 | response | provenance | |
+| testReactUseQueries.jsx:4:20:4:53 | await f ... e.com') | testReactUseQueries.jsx:4:9:4:53 | response | provenance | |
+| testReactUseQueries.jsx:4:26:4:53 | fetch(' ... e.com') | testReactUseQueries.jsx:4:20:4:53 | await f ... e.com') | provenance | |
+| testReactUseQueries.jsx:5:10:5:17 | response | testReactUseQueries.jsx:5:10:5:24 | response.json() | provenance | |
+| testReactUseQueries.jsx:5:10:5:24 | response.json() | testReactUseQueries.jsx:37:25:37:38 | repoQuery.data | provenance | |
| testUseQueries2.vue:6:11:6:63 | response | testUseQueries2.vue:7:24:7:31 | response | provenance | |
| testUseQueries2.vue:6:22:6:63 | await f ... ntent") | testUseQueries2.vue:6:11:6:63 | response | provenance | |
| testUseQueries2.vue:6:28:6:63 | fetch(" ... ntent") | testUseQueries2.vue:6:22:6:63 | await f ... ntent") | provenance | |
@@ -139,6 +145,12 @@ nodes
| testReactRelay.tsx:136:9:136:39 | data | semmle.label | data |
| testReactRelay.tsx:136:16:136:39 | readFra ... y, key) | semmle.label | readFra ... y, key) |
| testReactRelay.tsx:137:50:137:53 | data | semmle.label | data |
+| testReactUseQueries.jsx:4:9:4:53 | response | semmle.label | response |
+| testReactUseQueries.jsx:4:20:4:53 | await f ... e.com') | semmle.label | await f ... e.com') |
+| testReactUseQueries.jsx:4:26:4:53 | fetch(' ... e.com') | semmle.label | fetch(' ... e.com') |
+| testReactUseQueries.jsx:5:10:5:17 | response | semmle.label | response |
+| testReactUseQueries.jsx:5:10:5:24 | response.json() | semmle.label | response.json() |
+| testReactUseQueries.jsx:37:25:37:38 | repoQuery.data | semmle.label | repoQuery.data |
| testUseQueries2.vue:6:11:6:63 | response | semmle.label | response |
| testUseQueries2.vue:6:22:6:63 | await f ... ntent") | semmle.label | await f ... ntent") |
| testUseQueries2.vue:6:28:6:63 | fetch(" ... ntent") | semmle.label | fetch(" ... ntent") |
diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/testReactUseQueries.jsx b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/testReactUseQueries.jsx
index cd8fccad0ca1..d978e309c0f1 100644
--- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/testReactUseQueries.jsx
+++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/testReactUseQueries.jsx
@@ -1,7 +1,7 @@
import { useQueries } from '@tanstack/react-query';
const fetchRepoData = async () => {
- const response = await fetch('https://example.com'); // $ MISSING: Source
+ const response = await fetch('https://example.com'); // $ Source
return response.json();
};
@@ -34,7 +34,7 @@ export default function UseQueriesComponent() {
Content with Dangerous HTML
From 5dff23de6b302bd15429e96a61dc6cca3b81454b Mon Sep 17 00:00:00 2001
From: Napalys
Date: Thu, 13 Mar 2025 12:09:07 +0100
Subject: [PATCH 07/10] Added change note.
---
javascript/ql/lib/change-notes/2025-03-13-tanstack-vue.md | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 javascript/ql/lib/change-notes/2025-03-13-tanstack-vue.md
diff --git a/javascript/ql/lib/change-notes/2025-03-13-tanstack-vue.md b/javascript/ql/lib/change-notes/2025-03-13-tanstack-vue.md
new file mode 100644
index 000000000000..defc6c78bc2a
--- /dev/null
+++ b/javascript/ql/lib/change-notes/2025-03-13-tanstack-vue.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Added support for the `@tanstack/vue-query` package.
From 66737402c20fc83b3d3a654dcccf4b26c901b100 Mon Sep 17 00:00:00 2001
From: Napalys
Date: Fri, 14 Mar 2025 10:50:10 +0100
Subject: [PATCH 08/10] Updated test ouput with fixes from main.
---
.../DomBasedXssWithResponseThreat/Xss.expected | 11 +++++++++++
.../DomBasedXssWithResponseThreat/testUseQueries2.vue | 2 +-
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected
index 7c5081156a87..ad5dec8849d7 100644
--- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected
+++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected
@@ -15,6 +15,7 @@
| testReactRelay.tsx:137:50:137:53 | data | testReactRelay.tsx:136:16:136:39 | readFra ... y, key) | testReactRelay.tsx:137:50:137:53 | data | Cross-site scripting vulnerability due to $@. | testReactRelay.tsx:136:16:136:39 | readFra ... y, key) | user-provided value |
| testReactUseQueries.jsx:37:25:37:38 | repoQuery.data | testReactUseQueries.jsx:4:26:4:53 | fetch(' ... e.com') | testReactUseQueries.jsx:37:25:37:38 | repoQuery.data | Cross-site scripting vulnerability due to $@. | testReactUseQueries.jsx:4:26:4:53 | fetch(' ... e.com') | user-provided value |
| testUseQueries2.vue:40:10:40:23 | v-html=data3 | testUseQueries2.vue:6:28:6:63 | fetch(" ... ntent") | testUseQueries2.vue:40:10:40:23 | v-html=data3 | Cross-site scripting vulnerability due to $@. | testUseQueries2.vue:6:28:6:63 | fetch(" ... ntent") | user-provided value |
+| testUseQueries2.vue:40:10:40:23 | v-html=data3 | testUseQueries2.vue:12:28:12:41 | fetch("${id}") | testUseQueries2.vue:40:10:40:23 | v-html=data3 | Cross-site scripting vulnerability due to $@. | testUseQueries2.vue:12:28:12:41 | fetch("${id}") | user-provided value |
edges
| test.jsx:5:11:5:63 | response | test.jsx:6:24:6:31 | response | provenance | |
| test.jsx:5:22:5:63 | await f ... ntent") | test.jsx:5:11:5:63 | response | provenance | |
@@ -80,6 +81,11 @@ edges
| testUseQueries2.vue:7:24:7:31 | response | testUseQueries2.vue:7:24:7:38 | response.json() | provenance | |
| testUseQueries2.vue:7:24:7:38 | response.json() | testUseQueries2.vue:7:18:7:38 | await r ... .json() | provenance | |
| testUseQueries2.vue:8:12:8:15 | data | testUseQueries2.vue:33:22:33:36 | results[0].data | provenance | |
+| testUseQueries2.vue:12:11:12:41 | response | testUseQueries2.vue:13:12:13:19 | response | provenance | |
+| testUseQueries2.vue:12:22:12:41 | await fetch("${id}") | testUseQueries2.vue:12:11:12:41 | response | provenance | |
+| testUseQueries2.vue:12:28:12:41 | fetch("${id}") | testUseQueries2.vue:12:22:12:41 | await fetch("${id}") | provenance | |
+| testUseQueries2.vue:13:12:13:19 | response | testUseQueries2.vue:13:12:13:26 | response.json() | provenance | |
+| testUseQueries2.vue:13:12:13:26 | response.json() | testUseQueries2.vue:33:22:33:36 | results[0].data | provenance | |
| testUseQueries2.vue:33:22:33:36 | results[0].data | testUseQueries2.vue:40:10:40:23 | v-html=data3 | provenance | |
nodes
| test.jsx:5:11:5:63 | response | semmle.label | response |
@@ -159,6 +165,11 @@ nodes
| testUseQueries2.vue:7:24:7:31 | response | semmle.label | response |
| testUseQueries2.vue:7:24:7:38 | response.json() | semmle.label | response.json() |
| testUseQueries2.vue:8:12:8:15 | data | semmle.label | data |
+| testUseQueries2.vue:12:11:12:41 | response | semmle.label | response |
+| testUseQueries2.vue:12:22:12:41 | await fetch("${id}") | semmle.label | await fetch("${id}") |
+| testUseQueries2.vue:12:28:12:41 | fetch("${id}") | semmle.label | fetch("${id}") |
+| testUseQueries2.vue:13:12:13:19 | response | semmle.label | response |
+| testUseQueries2.vue:13:12:13:26 | response.json() | semmle.label | response.json() |
| testUseQueries2.vue:33:22:33:36 | results[0].data | semmle.label | results[0].data |
| testUseQueries2.vue:40:10:40:23 | v-html=data3 | semmle.label | v-html=data3 |
subpaths
diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/testUseQueries2.vue b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/testUseQueries2.vue
index 571d245b2335..8515e2d33ff8 100644
--- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/testUseQueries2.vue
+++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/testUseQueries2.vue
@@ -9,7 +9,7 @@ const fetchContent = async () => {
};
async function fetchPost() {
- const response = await fetch("${id}"); // $ MISSING: Source
+ const response = await fetch("${id}"); // $ Source
return response.json();
}
From d40ef0ddae56f30021344cf195f39a0a3f0a7394 Mon Sep 17 00:00:00 2001
From: Napalys
Date: Fri, 14 Mar 2025 13:48:15 +0100
Subject: [PATCH 09/10] Changed from `taint` to `value` steps.
Co-authored-by: Asgerf
---
javascript/ql/lib/ext/tanstack.model.yml | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/javascript/ql/lib/ext/tanstack.model.yml b/javascript/ql/lib/ext/tanstack.model.yml
index b9498a6af326..4db3702b2314 100644
--- a/javascript/ql/lib/ext/tanstack.model.yml
+++ b/javascript/ql/lib/ext/tanstack.model.yml
@@ -3,8 +3,8 @@ extensions:
pack: codeql/javascript-all
extensible: summaryModel
data:
- - ["@tanstack/angular-query-experimental", "Member[injectQuery]", "Argument[0].ReturnValue.Member[queryFn].ReturnValue", "ReturnValue.Member[data].Awaited", "taint"]
- - ["@tanstack/angular-query", "Member[injectQuery]", "Argument[0].ReturnValue.Member[queryFn].ReturnValue", "ReturnValue.Member[data].Awaited", "taint"]
- - ["@tanstack/vue-query", "Member[useQuery]", "Argument[0].Member[queryFn].ReturnValue.Awaited", "ReturnValue.Member[data]", "taint"]
- - ["@tanstack/vue-query", "Member[useQueries]", "Argument[0].Member[queries].ArrayElement.Member[queryFn].ReturnValue.Awaited", "ReturnValue.AnyMember.Member[data]", "taint"]
- - ["@tanstack/react-query", "Member[useQueries]", "Argument[0].Member[queries].ArrayElement.Member[queryFn].ReturnValue.Awaited", "ReturnValue.AnyMember.Member[data]", "taint"]
+ - ["@tanstack/angular-query-experimental", "Member[injectQuery]", "Argument[0].ReturnValue.Member[queryFn].ReturnValue", "ReturnValue.Member[data].Awaited", "value"]
+ - ["@tanstack/angular-query", "Member[injectQuery]", "Argument[0].ReturnValue.Member[queryFn].ReturnValue", "ReturnValue.Member[data].Awaited", "value"]
+ - ["@tanstack/vue-query", "Member[useQuery]", "Argument[0].Member[queryFn].ReturnValue.Awaited", "ReturnValue.Member[data]", "value"]
+ - ["@tanstack/vue-query", "Member[useQueries]", "Argument[0].Member[queries].ArrayElement.Member[queryFn].ReturnValue.Awaited", "ReturnValue.AnyMember.Member[data]", "value"]
+ - ["@tanstack/react-query", "Member[useQueries]", "Argument[0].Member[queries].ArrayElement.Member[queryFn].ReturnValue.Awaited", "ReturnValue.AnyMember.Member[data]", "value"]
From 933f3c6f77d7484a5887b07e7022f6f04c0d687d Mon Sep 17 00:00:00 2001
From: Napalys
Date: Fri, 14 Mar 2025 13:52:05 +0100
Subject: [PATCH 10/10] Refactor Tanstack integration: remove Tanstack
framework and added model as data for it instead.
---
javascript/ql/lib/ext/tanstack.model.yml | 1 +
javascript/ql/lib/javascript.qll | 1 -
.../semmle/javascript/frameworks/Tanstack.qll | 26 -------------------
.../Xss.expected | 4 ++-
4 files changed, 4 insertions(+), 28 deletions(-)
delete mode 100644 javascript/ql/lib/semmle/javascript/frameworks/Tanstack.qll
diff --git a/javascript/ql/lib/ext/tanstack.model.yml b/javascript/ql/lib/ext/tanstack.model.yml
index 4db3702b2314..d2b0bc0d782f 100644
--- a/javascript/ql/lib/ext/tanstack.model.yml
+++ b/javascript/ql/lib/ext/tanstack.model.yml
@@ -8,3 +8,4 @@ extensions:
- ["@tanstack/vue-query", "Member[useQuery]", "Argument[0].Member[queryFn].ReturnValue.Awaited", "ReturnValue.Member[data]", "value"]
- ["@tanstack/vue-query", "Member[useQueries]", "Argument[0].Member[queries].ArrayElement.Member[queryFn].ReturnValue.Awaited", "ReturnValue.AnyMember.Member[data]", "value"]
- ["@tanstack/react-query", "Member[useQueries]", "Argument[0].Member[queries].ArrayElement.Member[queryFn].ReturnValue.Awaited", "ReturnValue.AnyMember.Member[data]", "value"]
+ - ["@tanstack/react-query", "Member[useQuery]", "Argument[0].Member[queryFn].ReturnValue.Awaited", "ReturnValue.Member[data]", "value"]
diff --git a/javascript/ql/lib/javascript.qll b/javascript/ql/lib/javascript.qll
index b3bf7399a621..7bb2b7676105 100644
--- a/javascript/ql/lib/javascript.qll
+++ b/javascript/ql/lib/javascript.qll
@@ -139,7 +139,6 @@ import semmle.javascript.frameworks.Webix
import semmle.javascript.frameworks.WebSocket
import semmle.javascript.frameworks.XmlParsers
import semmle.javascript.frameworks.xUnit
-import semmle.javascript.frameworks.Tanstack
import semmle.javascript.linters.ESLint
import semmle.javascript.linters.JSLint
import semmle.javascript.linters.Linting
diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Tanstack.qll b/javascript/ql/lib/semmle/javascript/frameworks/Tanstack.qll
deleted file mode 100644
index 741079575963..000000000000
--- a/javascript/ql/lib/semmle/javascript/frameworks/Tanstack.qll
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * Provides classes and predicates modeling the Tanstack/react-query library.
- */
-
-private import javascript
-
-/**
- * An additional flow step that propagates data from the return value of the query function,
- * defined in a useQuery call from the '@tanstack/react-query' module, to the 'data' property.
- */
-private class TanstackStep extends DataFlow::AdditionalFlowStep {
- override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
- exists(API::CallNode useQuery |
- useQuery = useQueryCall() and
- node1 = useQuery.getParameter(0).getMember("queryFn").getReturn().getPromised().asSink() and
- node2 = useQuery.getReturn().getMember("data").asSource()
- )
- }
-}
-
-/**
- * Retrieves a call node representing a useQuery invocation from the '@tanstack/react-query' module.
- */
-private API::CallNode useQueryCall() {
- result = API::moduleImport("@tanstack/react-query").getMember("useQuery").getACall()
-}
diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected
index ad5dec8849d7..7aa3957d64d8 100644
--- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected
+++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected
@@ -24,8 +24,9 @@ edges
| test.jsx:6:18:6:38 | await r ... .json() | test.jsx:6:11:6:38 | data | provenance | |
| test.jsx:6:24:6:31 | response | test.jsx:6:24:6:38 | response.json() | provenance | |
| test.jsx:6:24:6:38 | response.json() | test.jsx:6:18:6:38 | await r ... .json() | provenance | |
-| test.jsx:7:12:7:15 | data | test.jsx:15:11:17:5 | data | provenance | |
+| test.jsx:7:12:7:15 | data | test.jsx:15:13:15:16 | data | provenance | |
| test.jsx:15:11:17:5 | data | test.jsx:27:29:27:32 | data | provenance | |
+| test.jsx:15:13:15:16 | data | test.jsx:15:11:17:5 | data | provenance | |
| test.ts:8:9:8:79 | this.#h ... query') | test.ts:20:28:20:35 | response | provenance | |
| test.ts:20:28:20:35 | response | test.ts:21:57:21:64 | response | provenance | |
| test.ts:20:28:20:35 | response | test.ts:24:43:24:50 | response | provenance | |
@@ -97,6 +98,7 @@ nodes
| test.jsx:6:24:6:38 | response.json() | semmle.label | response.json() |
| test.jsx:7:12:7:15 | data | semmle.label | data |
| test.jsx:15:11:17:5 | data | semmle.label | data |
+| test.jsx:15:13:15:16 | data | semmle.label | data |
| test.jsx:27:29:27:32 | data | semmle.label | data |
| test.ts:8:9:8:79 | this.#h ... query') | semmle.label | this.#h ... query') |
| test.ts:20:28:20:35 | response | semmle.label | response |