From 05690c21ed8cd1a803c8b5541de94d74f947adc4 Mon Sep 17 00:00:00 2001 From: Napalys Date: Fri, 21 Feb 2025 12:51:39 +0100 Subject: [PATCH 1/7] Added a test for tanstack/react-query useQuery --- .../Xss.expected | 4 +++ .../DomBasedXssWithResponseThreat/Xss.ext.yml | 6 ++++ .../DomBasedXssWithResponseThreat/Xss.qlref | 2 ++ .../DomBasedXssWithResponseThreat/test.jsx | 32 +++++++++++++++++++ 4 files changed, 44 insertions(+) create mode 100644 javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.ext.yml create mode 100644 javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/test.jsx 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 new file mode 100644 index 000000000000..58f42bec0c84 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.expected @@ -0,0 +1,4 @@ +#select +edges +nodes +subpaths diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.ext.yml b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.ext.yml new file mode 100644 index 000000000000..e364808a3497 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.ext.yml @@ -0,0 +1,6 @@ +extensions: + - addsTo: + pack: codeql/threat-models + extensible: threatModelConfiguration + data: + - ["response", true, 0] diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.qlref b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.qlref new file mode 100644 index 000000000000..22add04d21de --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/Xss.qlref @@ -0,0 +1,2 @@ +query: Security/CWE-079/Xss.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/test.jsx b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/test.jsx new file mode 100644 index 000000000000..21093ae8b928 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/test.jsx @@ -0,0 +1,32 @@ +import React from "react"; +import { useQuery } from "@tanstack/react-query"; + +const fetchContent = async () => { + const response = await fetch("https://example.com/content"); // $ MISSING: Source[js/xss] + const data = await response.json(); + return data; +}; + +const ContentWithDangerousHtml = () => { + const { data, error, isLoading } = useQuery( + { + queryFn: fetchContent + } + ); + + if (isLoading) return
Loading...
; + if (error) return
Error fetching content!
; + + return ( +
+

Content with Dangerous HTML

+
+
+ ); +}; + +export default ContentWithDangerousHtml; From 1227a7eedc97eed81a0e9b0f2d11d010a28741bb Mon Sep 17 00:00:00 2001 From: Napalys Date: Fri, 21 Feb 2025 12:55:33 +0100 Subject: [PATCH 2/7] Add Tanstack framework support and enhance data flow tracking for fetch responses --- javascript/ql/lib/javascript.qll | 1 + .../javascript/frameworks/ClientRequests.qll | 19 ++++++++++++++++ .../semmle/javascript/frameworks/Fetch.qll | 11 ++++++++++ .../semmle/javascript/frameworks/Tanstack.qll | 22 +++++++++++++++++++ .../Xss.expected | 20 +++++++++++++++++ .../DomBasedXssWithResponseThreat/test.jsx | 4 ++-- 6 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 javascript/ql/lib/semmle/javascript/frameworks/Fetch.qll create mode 100644 javascript/ql/lib/semmle/javascript/frameworks/Tanstack.qll diff --git a/javascript/ql/lib/javascript.qll b/javascript/ql/lib/javascript.qll index 7bb2b7676105..b3bf7399a621 100644 --- a/javascript/ql/lib/javascript.qll +++ b/javascript/ql/lib/javascript.qll @@ -139,6 +139,7 @@ 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/ClientRequests.qll b/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll index 13879fda3e7d..2cd7d81b0adf 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll @@ -861,4 +861,23 @@ module ClientRequest { result = form.getMember("append").getACall().getParameter(1).asSink() } } + + private class ClientRequestThreatModel extends ThreatModelSource::Range { + ClientRequestThreatModel() { this = any(ClientRequest r).getAResponseDataNode() } + + override string getThreatModel() { result = "response" } + + override string getSourceType() { result = "HTTP response data" } + } + + class FetchResponseStep extends TaintTracking::AdditionalTaintStep { + override predicate step(DataFlow::Node node1, DataFlow::Node node2) { + exists(DataFlow::MethodCallNode call | + call.getMethodName() in ["json", "text", "blob", "arrayBuffer"] and + node1 = call.getReceiver() and + node2 = call and + call.getNumArgument() = 0 + ) + } + } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Fetch.qll b/javascript/ql/lib/semmle/javascript/frameworks/Fetch.qll new file mode 100644 index 000000000000..2a612b90bdb8 --- /dev/null +++ b/javascript/ql/lib/semmle/javascript/frameworks/Fetch.qll @@ -0,0 +1,11 @@ +private import javascript + +class Fetch extends DataFlow::AdditionalFlowStep { + override predicate step(DataFlow::Node node1, DataFlow::Node node2) { + exists(DataFlow::MethodCallNode call | + call.getMethodName() in ["json", "text", "blob", "arrayBuffer"] and + node1 = call.getReceiver() and + node2 = call + ) + } +} diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Tanstack.qll b/javascript/ql/lib/semmle/javascript/frameworks/Tanstack.qll new file mode 100644 index 000000000000..cc66bc928271 --- /dev/null +++ b/javascript/ql/lib/semmle/javascript/frameworks/Tanstack.qll @@ -0,0 +1,22 @@ +private import javascript + +class TanstackStep extends DataFlow::AdditionalFlowStep { + override predicate step(DataFlow::Node node1, DataFlow::Node node2) { + exists(DataFlow::CallNode useQuery | + useQuery = useQueryCall() and + node1 = + useQuery + .getArgument(0) + .getALocalSource() + .getAPropertyWrite("queryFn") + .getRhs() + .getAFunctionValue() + .getAReturn() and + node2 = useQuery.getAPropertyRead("data") + ) + } +} + +DataFlow::CallNode useQueryCall() { + result = DataFlow::moduleImport("@tanstack/react-query").getAPropertyRead("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 58f42bec0c84..9d50a2e61284 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,4 +1,24 @@ #select +| test.jsx:25:29:25:32 | data | test.jsx:5:28:5:63 | fetch(" ... ntent") | test.jsx:25:29:25:32 | data | Cross-site scripting vulnerability due to $@. | test.jsx:5:28:5: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 | | +| test.jsx:5:28:5:63 | fetch(" ... ntent") | test.jsx:5:22:5:63 | await f ... ntent") | provenance | | +| test.jsx:6:11:6:38 | data | test.jsx:7:12:7:15 | data | provenance | | +| 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:11:11:15:5 | data | provenance | | +| test.jsx:11:11:15:5 | data | test.jsx:25:29:25:32 | data | 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") | +| test.jsx:5:28:5:63 | fetch(" ... ntent") | semmle.label | fetch(" ... ntent") | +| test.jsx:6:11:6:38 | data | semmle.label | data | +| test.jsx:6:18:6:38 | await r ... .json() | semmle.label | await r ... .json() | +| test.jsx:6:24:6:31 | response | semmle.label | response | +| test.jsx:6:24:6:38 | response.json() | semmle.label | response.json() | +| test.jsx:7:12:7:15 | data | semmle.label | data | +| test.jsx:11:11:15:5 | data | semmle.label | data | +| test.jsx:25:29:25:32 | data | semmle.label | data | subpaths diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/test.jsx b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/test.jsx index 21093ae8b928..57d00ba56338 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/test.jsx +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/test.jsx @@ -2,7 +2,7 @@ import React from "react"; import { useQuery } from "@tanstack/react-query"; const fetchContent = async () => { - const response = await fetch("https://example.com/content"); // $ MISSING: Source[js/xss] + const response = await fetch("https://example.com/content"); // $ Source[js/xss] const data = await response.json(); return data; }; @@ -22,7 +22,7 @@ const ContentWithDangerousHtml = () => {

Content with Dangerous HTML

From ab0241c1dec5003b83155d5ebc00117507eda3ec Mon Sep 17 00:00:00 2001 From: Napalys Date: Fri, 21 Feb 2025 13:04:18 +0100 Subject: [PATCH 3/7] Added missing doc strings for Tanstack queries --- .../semmle/javascript/frameworks/ClientRequests.qll | 8 ++++++++ .../ql/lib/semmle/javascript/frameworks/Fetch.qll | 8 ++++++++ .../ql/lib/semmle/javascript/frameworks/Tanstack.qll | 11 +++++++++++ 3 files changed, 27 insertions(+) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll b/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll index 2cd7d81b0adf..2f675647a0d4 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll @@ -862,6 +862,10 @@ module ClientRequest { } } + /** + * Threat model source representing HTTP response data. + * Marks nodes originating from a client request's response data as tainted. + */ private class ClientRequestThreatModel extends ThreatModelSource::Range { ClientRequestThreatModel() { this = any(ClientRequest r).getAResponseDataNode() } @@ -870,6 +874,10 @@ module ClientRequest { override string getSourceType() { result = "HTTP response data" } } + /** + * An additional taint step that captures taint propagation from the receiver of fetch response methods + * (such as "json", "text", "blob", and "arrayBuffer") to the call result. + */ class FetchResponseStep extends TaintTracking::AdditionalTaintStep { override predicate step(DataFlow::Node node1, DataFlow::Node node2) { exists(DataFlow::MethodCallNode call | diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Fetch.qll b/javascript/ql/lib/semmle/javascript/frameworks/Fetch.qll index 2a612b90bdb8..bae57eebfe9b 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Fetch.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Fetch.qll @@ -1,5 +1,13 @@ +/** + * Provides an additional flow step that propagates data from the receiver of fetch response methods. + */ + private import javascript +/** + * An additional flow step that propagates data from the receiver of fetch response methods + * (like "json", "text", "blob", and "arrayBuffer") to the call result. + */ class Fetch extends DataFlow::AdditionalFlowStep { override predicate step(DataFlow::Node node1, DataFlow::Node node2) { exists(DataFlow::MethodCallNode call | diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Tanstack.qll b/javascript/ql/lib/semmle/javascript/frameworks/Tanstack.qll index cc66bc928271..c929e51f7376 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Tanstack.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Tanstack.qll @@ -1,5 +1,13 @@ +/** + * 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. + */ class TanstackStep extends DataFlow::AdditionalFlowStep { override predicate step(DataFlow::Node node1, DataFlow::Node node2) { exists(DataFlow::CallNode useQuery | @@ -17,6 +25,9 @@ class TanstackStep extends DataFlow::AdditionalFlowStep { } } +/** + * Retrieves a call node representing a useQuery invocation from the '@tanstack/react-query' module. + */ DataFlow::CallNode useQueryCall() { result = DataFlow::moduleImport("@tanstack/react-query").getAPropertyRead("useQuery").getACall() } From 3587ba593af92d8007ed5d0f34c4da93c1790a33 Mon Sep 17 00:00:00 2001 From: Napalys Date: Fri, 21 Feb 2025 13:47:48 +0100 Subject: [PATCH 4/7] Add change note and added tanstack to supported framework list --- docs/codeql/reusables/supported-frameworks.rst | 1 + javascript/ql/lib/change-notes/2025-02-21-tanstack.md | 4 ++++ 2 files changed, 5 insertions(+) create mode 100644 javascript/ql/lib/change-notes/2025-02-21-tanstack.md diff --git a/docs/codeql/reusables/supported-frameworks.rst b/docs/codeql/reusables/supported-frameworks.rst index 68ce952f70f3..16504b18d0c1 100644 --- a/docs/codeql/reusables/supported-frameworks.rst +++ b/docs/codeql/reusables/supported-frameworks.rst @@ -181,6 +181,7 @@ and the CodeQL library pack ``codeql/javascript-all`` (`changelog Date: Mon, 24 Feb 2025 11:15:55 +0100 Subject: [PATCH 5/7] Updated tanstack to use API graph. --- .../semmle/javascript/frameworks/Tanstack.qll | 17 +++++------------ .../DomBasedXssWithResponseThreat/Xss.expected | 10 +++++----- .../DomBasedXssWithResponseThreat/test.jsx | 10 ++++++---- .../DomBasedXssWithResponseThreat/wrapper.js | 2 ++ 4 files changed, 18 insertions(+), 21 deletions(-) create mode 100644 javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/wrapper.js diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Tanstack.qll b/javascript/ql/lib/semmle/javascript/frameworks/Tanstack.qll index c929e51f7376..dce8b77a3ddb 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Tanstack.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Tanstack.qll @@ -10,17 +10,10 @@ private import javascript */ class TanstackStep extends DataFlow::AdditionalFlowStep { override predicate step(DataFlow::Node node1, DataFlow::Node node2) { - exists(DataFlow::CallNode useQuery | + exists(API::CallNode useQuery | useQuery = useQueryCall() and - node1 = - useQuery - .getArgument(0) - .getALocalSource() - .getAPropertyWrite("queryFn") - .getRhs() - .getAFunctionValue() - .getAReturn() and - node2 = useQuery.getAPropertyRead("data") + node1 = useQuery.getParameter(0).getMember("queryFn").getReturn().getPromised().asSink() and + node2 = useQuery.getReturn().getMember("data").asSource() ) } } @@ -28,6 +21,6 @@ class TanstackStep extends DataFlow::AdditionalFlowStep { /** * Retrieves a call node representing a useQuery invocation from the '@tanstack/react-query' module. */ -DataFlow::CallNode useQueryCall() { - result = DataFlow::moduleImport("@tanstack/react-query").getAPropertyRead("useQuery").getACall() +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 9d50a2e61284..f83c9f40b315 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,5 @@ #select -| test.jsx:25:29:25:32 | data | test.jsx:5:28:5:63 | fetch(" ... ntent") | test.jsx:25:29:25:32 | data | Cross-site scripting vulnerability due to $@. | test.jsx:5:28:5:63 | fetch(" ... ntent") | user-provided value | +| 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 | 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 | | @@ -8,8 +8,8 @@ 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:11:11:15:5 | data | provenance | | -| test.jsx:11:11:15:5 | data | test.jsx:25:29:25:32 | data | 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 | | 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") | @@ -19,6 +19,6 @@ nodes | test.jsx:6:24:6:31 | response | semmle.label | response | | test.jsx:6:24:6:38 | response.json() | semmle.label | response.json() | | test.jsx:7:12:7:15 | data | semmle.label | data | -| test.jsx:11:11:15:5 | data | semmle.label | data | -| test.jsx:25:29:25:32 | data | semmle.label | data | +| test.jsx:15:11:17:5 | data | semmle.label | data | +| test.jsx:27:29:27:32 | data | semmle.label | data | subpaths diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/test.jsx b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/test.jsx index 57d00ba56338..26d24167b424 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/test.jsx +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/test.jsx @@ -1,5 +1,5 @@ import React from "react"; -import { useQuery } from "@tanstack/react-query"; +import { useQuery } from "./wrapper"; const fetchContent = async () => { const response = await fetch("https://example.com/content"); // $ Source[js/xss] @@ -7,11 +7,13 @@ const fetchContent = async () => { return data; }; +const getQueryOptions = () => { + return {queryFn: fetchContent}; +} + const ContentWithDangerousHtml = () => { const { data, error, isLoading } = useQuery( - { - queryFn: fetchContent - } + getQueryOptions() ); if (isLoading) return
Loading...
; diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/wrapper.js b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/wrapper.js new file mode 100644 index 000000000000..0a63a160d5d1 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXssWithResponseThreat/wrapper.js @@ -0,0 +1,2 @@ +import { useQuery } from "@tanstack/react-query"; +export { useQuery} From bf77ffef37ebf0138b1cc5d3125e2825d5fd9a0c Mon Sep 17 00:00:00 2001 From: Napalys Date: Tue, 25 Feb 2025 13:48:50 +0100 Subject: [PATCH 6/7] Applied comment Co-authored-by: Asgerf --- .../codeql/reusables/supported-frameworks.rst | 1 - .../lib/change-notes/2025-02-21-tanstack.md | 2 +- .../javascript/frameworks/ClientRequests.qll | 2 +- .../semmle/javascript/frameworks/Fetch.qll | 19 ------------------- .../semmle/javascript/frameworks/Tanstack.qll | 4 ++-- .../DomBasedXssWithResponseThreat/wrapper.js | 2 +- 6 files changed, 5 insertions(+), 25 deletions(-) delete mode 100644 javascript/ql/lib/semmle/javascript/frameworks/Fetch.qll diff --git a/docs/codeql/reusables/supported-frameworks.rst b/docs/codeql/reusables/supported-frameworks.rst index 16504b18d0c1..68ce952f70f3 100644 --- a/docs/codeql/reusables/supported-frameworks.rst +++ b/docs/codeql/reusables/supported-frameworks.rst @@ -181,7 +181,6 @@ and the CodeQL library pack ``codeql/javascript-all`` (`changelog Date: Tue, 25 Feb 2025 15:22:14 +0100 Subject: [PATCH 7/7] Updated change note with `response` threat model info. Co-authored-by: Asgerf --- javascript/ql/lib/change-notes/2025-02-21-tanstack.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/javascript/ql/lib/change-notes/2025-02-21-tanstack.md b/javascript/ql/lib/change-notes/2025-02-21-tanstack.md index 13013e16df43..49169ddc943f 100644 --- a/javascript/ql/lib/change-notes/2025-02-21-tanstack.md +++ b/javascript/ql/lib/change-notes/2025-02-21-tanstack.md @@ -1,4 +1,6 @@ --- -category: minorAnalysis +category: majorAnalysis --- +--- +* Added support for the `response` threat model kind, which can enabled with [advanced setup](https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning#extending-codeql-coverage-with-threat-models). When enabled, the response data coming back from an outgoing HTTP request is considered a source of taint. * Added support for the `useQuery` hook from `@tanstack/react-query`.