From c001435258539ee66b5ff4cf62913eb64fae9742 Mon Sep 17 00:00:00 2001
From: Napalys
Date: Tue, 11 Mar 2025 12:32:24 +0100
Subject: [PATCH 1/6] Refactor Angular2 API to use `httpClientApiNode` for
`HttpClient` method calls
---
.../ql/lib/semmle/javascript/frameworks/Angular2.qll | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Angular2.qll b/javascript/ql/lib/semmle/javascript/frameworks/Angular2.qll
index a2702dbc7429..3441b5d9c006 100644
--- a/javascript/ql/lib/semmle/javascript/frameworks/Angular2.qll
+++ b/javascript/ql/lib/semmle/javascript/frameworks/Angular2.qll
@@ -190,13 +190,16 @@ module Angular2 {
result.hasUnderlyingType("@angular/common/http", "HttpClient")
}
+ /** Gets a reference to an `HttpClient` object using the API graph. */
+ API::Node httpClientApiNode() { result = API::Node::ofType("@angular/common/http", "HttpClient") }
+
private class AngularClientRequest extends ClientRequest::Range, DataFlow::MethodCallNode {
int argumentOffset;
AngularClientRequest() {
- this = httpClient().getAMethodCall("request") and argumentOffset = 1
+ this = httpClientApiNode().getMember("request").getACall() and argumentOffset = 1
or
- this = httpClient().getAMethodCall() and
+ this = httpClientApiNode().getAMember().getACall() and
not this.getMethodName() = "request" and
argumentOffset = 0
}
From 184d23df46326328e503316bd82833b147921182 Mon Sep 17 00:00:00 2001
From: Napalys
Date: Tue, 11 Mar 2025 12:34:53 +0100
Subject: [PATCH 2/6] Add test cases for `@tanstack/angular-query-experimental`
`injectQuery`
---
.../Xss.expected | 4 ++
.../DomBasedXssWithResponseThreat/test.ts | 37 +++++++++++++++++++
2 files changed, 41 insertions(+)
create mode 100644 javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/test.ts
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 b2be2a7bcc2e..51db8cfc3ca3 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
@@ -92,3 +92,7 @@ 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.ts:8:82:8:92 | // $ Source | Missing result: Source |
+| test.ts:21:79:21:88 | // $ Alert | Missing result: Alert |
+| test.ts:24:94:24:103 | // $ Alert | Missing result: Alert |
diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/test.ts b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/test.ts
new file mode 100644
index 000000000000..fb7ffae102ad
--- /dev/null
+++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/test.ts
@@ -0,0 +1,37 @@
+import { QueryClient, injectQuery } from '@tanstack/angular-query-experimental'
+import { HttpClient } from '@angular/common/http'
+
+class ServiceOrComponent {
+ query = injectQuery(() => ({
+ queryKey: ['repoData'],
+ queryFn: () =>
+ this.#http.get('https://api.github.com/repos/tanstack/query'), // $ Source
+ }))
+
+ #http: {
+ get: (url: string) => Promise
+ };
+
+ constructor(http: HttpClient) {
+ this.#http = http;
+ }
+
+ displayRepoDetails() {
+ this.query.data.then(response => {
+ document.getElementById('repoInfo').innerHTML = response.description; // $ Alert
+
+ const detailsElement = document.createElement('div');
+ detailsElement.innerHTML = `${response.name}
${response.owner.bio}
`; // $ Alert
+ document.body.appendChild(detailsElement);
+ });
+ }
+}
+
+interface Response {
+ name: string;
+ description: string;
+ stargazers_count: number;
+ owner: {
+ bio: string;
+ }
+}
From 770920e738fc04b8f7ebbbb7574e2c84f124e517 Mon Sep 17 00:00:00 2001
From: Napalys
Date: Tue, 11 Mar 2025 13:27:30 +0100
Subject: [PATCH 3/6] Add new model configuration for
`@tanstack/angular-query-experimental`.
---
javascript/ql/lib/ext/tanstack.model.yml | 6 +++++
.../Xss.expected | 24 +++++++++++++++----
2 files changed, 26 insertions(+), 4 deletions(-)
create mode 100644 javascript/ql/lib/ext/tanstack.model.yml
diff --git a/javascript/ql/lib/ext/tanstack.model.yml b/javascript/ql/lib/ext/tanstack.model.yml
new file mode 100644
index 000000000000..cd96b2426b58
--- /dev/null
+++ b/javascript/ql/lib/ext/tanstack.model.yml
@@ -0,0 +1,6 @@
+extensions:
+ - addsTo:
+ pack: codeql/javascript-all
+ extensible: summaryModel
+ data:
+ - ["@tanstack/angular-query-experimental", "Member[injectQuery]", "Argument[0].ReturnValue.Member[queryFn].ReturnValue", "ReturnValue.Member[data].Awaited", "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 51db8cfc3ca3..313febe21946 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
@@ -1,5 +1,7 @@
#select
| 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 |
| 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 |
@@ -20,6 +22,15 @@ edges
| 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:15:11:17:5 | data | test.jsx:27:29:27:32 | 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 | |
+| test.ts:20:28:20:35 | response | test.ts:24:67:24:74 | response | provenance | |
+| test.ts:21:57:21:64 | response | test.ts:21:57:21:76 | response.description | provenance | |
+| test.ts:24:43:24:50 | response | test.ts:24:43:24:55 | response.name | provenance | |
+| 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 | |
| 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 | |
@@ -56,6 +67,15 @@ nodes
| test.jsx:7:12:7:15 | data | semmle.label | data |
| test.jsx:15:11:17:5 | 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 |
+| test.ts:21:57:21:64 | response | semmle.label | response |
+| test.ts:21:57:21:76 | response.description | semmle.label | response.description |
+| test.ts:24:36:24:90 | `${ ... o}` | semmle.label | `${ ... o}` |
+| test.ts:24:43:24:50 | response | semmle.label | response |
+| 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 |
| 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 |
@@ -92,7 +112,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.ts:8:82:8:92 | // $ Source | Missing result: Source |
-| test.ts:21:79:21:88 | // $ Alert | Missing result: Alert |
-| test.ts:24:94:24:103 | // $ Alert | Missing result: Alert |
From 09986bc26c3ea6849544d97216df13c9ff734b3d Mon Sep 17 00:00:00 2001
From: Napalys
Date: Tue, 11 Mar 2025 13:42:37 +0100
Subject: [PATCH 4/6] Added change note.
---
.../ql/lib/change-notes/2025-03-11-tanstack-angular.md | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 javascript/ql/lib/change-notes/2025-03-11-tanstack-angular.md
diff --git a/javascript/ql/lib/change-notes/2025-03-11-tanstack-angular.md b/javascript/ql/lib/change-notes/2025-03-11-tanstack-angular.md
new file mode 100644
index 000000000000..5f208358f8fd
--- /dev/null
+++ b/javascript/ql/lib/change-notes/2025-03-11-tanstack-angular.md
@@ -0,0 +1,5 @@
+---
+category: minorAnalysis
+---
+* Added support for the `@tanstack/angular-query-experimental`.
+* Improved `Angular Client Request` flow.
From bf24f7794f08ec07add5d15d20dedbc4781ef9bd Mon Sep 17 00:00:00 2001
From: Napalys Klicius
Date: Wed, 12 Mar 2025 13:58:09 +0100
Subject: [PATCH 5/6] Update
javascript/ql/lib/change-notes/2025-03-11-tanstack-angular.md
Co-authored-by: Asger F
---
javascript/ql/lib/change-notes/2025-03-11-tanstack-angular.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/javascript/ql/lib/change-notes/2025-03-11-tanstack-angular.md b/javascript/ql/lib/change-notes/2025-03-11-tanstack-angular.md
index 5f208358f8fd..5c4eb99eed76 100644
--- a/javascript/ql/lib/change-notes/2025-03-11-tanstack-angular.md
+++ b/javascript/ql/lib/change-notes/2025-03-11-tanstack-angular.md
@@ -1,5 +1,5 @@
---
category: minorAnalysis
---
-* Added support for the `@tanstack/angular-query-experimental`.
-* Improved `Angular Client Request` flow.
+* Added support for the `@tanstack/angular-query-experimental` package.
+* Improved support for the `@angular/common/http` package, detecting outgoing HTTP requests in more cases.
From f867e0fae85956a5fa33fd2a4b58896b72e42355 Mon Sep 17 00:00:00 2001
From: Napalys
Date: Wed, 12 Mar 2025 14:00:23 +0100
Subject: [PATCH 6/6] Added `angular-query` so when it is released it would be
still modeled.
---
javascript/ql/lib/ext/tanstack.model.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/javascript/ql/lib/ext/tanstack.model.yml b/javascript/ql/lib/ext/tanstack.model.yml
index cd96b2426b58..19b57eae6124 100644
--- a/javascript/ql/lib/ext/tanstack.model.yml
+++ b/javascript/ql/lib/ext/tanstack.model.yml
@@ -4,3 +4,4 @@ extensions:
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"]