From 7f9b8557ac1c2fb3be684960bebdf957efc869ae Mon Sep 17 00:00:00 2001 From: tyage Date: Sat, 8 Apr 2023 18:18:34 +0900 Subject: [PATCH 1/4] Add Next.js router push as XSS sink --- .../ClientSideUrlRedirectCustomizations.qll | 2 ++ .../Security/CWE-079/DomBasedXss/Xss.expected | 32 +++++++++++++++++++ .../XssWithAdditionalSources.expected | 30 +++++++++++++++++ .../CWE-079/DomBasedXss/react-use-router.js | 23 +++++++++++++ 4 files changed, 87 insertions(+) create mode 100644 javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/react-use-router.js diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll index 98d85d887414..de19e549f9c3 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll @@ -231,6 +231,8 @@ module ClientSideUrlRedirect { NextRoutePushUrlSink() { this = NextJS::nextRouter().getAMemberCall(["push", "replace"]).getArgument(0) } + + override predicate isXssSink() { any() } } private class SinkFromModel extends Sink { diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected index d40a652b962f..ddf5bbb51b27 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected @@ -560,6 +560,20 @@ nodes | react-use-context.js:16:26:16:36 | window.name | | react-use-context.js:16:26:16:36 | window.name | | react-use-context.js:16:26:16:36 | window.name | +| react-use-router.js:5:9:5:28 | router | +| react-use-router.js:5:18:5:28 | useRouter() | +| react-use-router.js:9:21:9:26 | router | +| react-use-router.js:9:21:9:32 | router.query | +| react-use-router.js:9:21:9:32 | router.query | +| react-use-router.js:9:21:9:39 | router.query.foobar | +| react-use-router.js:9:21:9:39 | router.query.foobar | +| react-use-router.js:20:15:20:24 | router | +| react-use-router.js:20:17:20:22 | router | +| react-use-router.js:21:43:21:48 | router | +| react-use-router.js:21:43:21:54 | router.query | +| react-use-router.js:21:43:21:54 | router.query | +| react-use-router.js:21:43:21:61 | router.query.foobar | +| react-use-router.js:21:43:21:61 | router.query.foobar | | react-use-state.js:4:9:4:49 | state | | react-use-state.js:4:9:4:49 | state | | react-use-state.js:4:10:4:14 | state | @@ -1700,6 +1714,22 @@ edges | react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted | | react-use-context.js:10:22:10:32 | window.name | react-use-context.js:10:22:10:32 | window.name | | react-use-context.js:16:26:16:36 | window.name | react-use-context.js:16:26:16:36 | window.name | +| react-use-router.js:5:9:5:28 | router | react-use-router.js:9:21:9:26 | router | +| react-use-router.js:5:18:5:28 | useRouter() | react-use-router.js:5:9:5:28 | router | +| react-use-router.js:9:21:9:26 | router | react-use-router.js:9:21:9:32 | router.query | +| react-use-router.js:9:21:9:32 | router.query | react-use-router.js:9:21:9:39 | router.query.foobar | +| react-use-router.js:9:21:9:32 | router.query | react-use-router.js:9:21:9:39 | router.query.foobar | +| react-use-router.js:9:21:9:32 | router.query | react-use-router.js:9:21:9:39 | router.query.foobar | +| react-use-router.js:9:21:9:32 | router.query | react-use-router.js:9:21:9:39 | router.query.foobar | +| react-use-router.js:9:21:9:39 | router.query.foobar | react-use-router.js:5:18:5:28 | useRouter() | +| react-use-router.js:20:15:20:24 | router | react-use-router.js:21:43:21:48 | router | +| react-use-router.js:20:17:20:22 | router | react-use-router.js:20:15:20:24 | router | +| react-use-router.js:21:43:21:48 | router | react-use-router.js:21:43:21:54 | router.query | +| react-use-router.js:21:43:21:54 | router.query | react-use-router.js:21:43:21:61 | router.query.foobar | +| react-use-router.js:21:43:21:54 | router.query | react-use-router.js:21:43:21:61 | router.query.foobar | +| react-use-router.js:21:43:21:54 | router.query | react-use-router.js:21:43:21:61 | router.query.foobar | +| react-use-router.js:21:43:21:54 | router.query | react-use-router.js:21:43:21:61 | router.query.foobar | +| react-use-router.js:21:43:21:61 | router.query.foobar | react-use-router.js:20:17:20:22 | router | | react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state | | react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state | | react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state | @@ -2386,6 +2416,8 @@ edges | react-native.js:9:27:9:33 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:9:27:9:33 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value | | react-use-context.js:10:22:10:32 | window.name | react-use-context.js:10:22:10:32 | window.name | react-use-context.js:10:22:10:32 | window.name | Cross-site scripting vulnerability due to $@. | react-use-context.js:10:22:10:32 | window.name | user-provided value | | react-use-context.js:16:26:16:36 | window.name | react-use-context.js:16:26:16:36 | window.name | react-use-context.js:16:26:16:36 | window.name | Cross-site scripting vulnerability due to $@. | react-use-context.js:16:26:16:36 | window.name | user-provided value | +| react-use-router.js:9:21:9:39 | router.query.foobar | react-use-router.js:9:21:9:32 | router.query | react-use-router.js:9:21:9:39 | router.query.foobar | Cross-site scripting vulnerability due to $@. | react-use-router.js:9:21:9:32 | router.query | user-provided value | +| react-use-router.js:21:43:21:61 | router.query.foobar | react-use-router.js:21:43:21:54 | router.query | react-use-router.js:21:43:21:61 | router.query.foobar | Cross-site scripting vulnerability due to $@. | react-use-router.js:21:43:21:54 | router.query | user-provided value | | react-use-state.js:5:51:5:55 | state | react-use-state.js:4:38:4:48 | window.name | react-use-state.js:5:51:5:55 | state | Cross-site scripting vulnerability due to $@. | react-use-state.js:4:38:4:48 | window.name | user-provided value | | react-use-state.js:11:51:11:55 | state | react-use-state.js:10:14:10:24 | window.name | react-use-state.js:11:51:11:55 | state | Cross-site scripting vulnerability due to $@. | react-use-state.js:10:14:10:24 | window.name | user-provided value | | react-use-state.js:17:51:17:55 | state | react-use-state.js:16:20:16:30 | window.name | react-use-state.js:17:51:17:55 | state | Cross-site scripting vulnerability due to $@. | react-use-state.js:16:20:16:30 | window.name | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected index 5e5010d126e1..e9b676b4a272 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected @@ -572,6 +572,20 @@ nodes | react-use-context.js:16:26:16:36 | window.name | | react-use-context.js:16:26:16:36 | window.name | | react-use-context.js:16:26:16:36 | window.name | +| react-use-router.js:5:9:5:28 | router | +| react-use-router.js:5:18:5:28 | useRouter() | +| react-use-router.js:9:21:9:26 | router | +| react-use-router.js:9:21:9:32 | router.query | +| react-use-router.js:9:21:9:32 | router.query | +| react-use-router.js:9:21:9:39 | router.query.foobar | +| react-use-router.js:9:21:9:39 | router.query.foobar | +| react-use-router.js:20:15:20:24 | router | +| react-use-router.js:20:17:20:22 | router | +| react-use-router.js:21:43:21:48 | router | +| react-use-router.js:21:43:21:54 | router.query | +| react-use-router.js:21:43:21:54 | router.query | +| react-use-router.js:21:43:21:61 | router.query.foobar | +| react-use-router.js:21:43:21:61 | router.query.foobar | | react-use-state.js:4:9:4:49 | state | | react-use-state.js:4:9:4:49 | state | | react-use-state.js:4:10:4:14 | state | @@ -1762,6 +1776,22 @@ edges | react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted | | react-use-context.js:10:22:10:32 | window.name | react-use-context.js:10:22:10:32 | window.name | | react-use-context.js:16:26:16:36 | window.name | react-use-context.js:16:26:16:36 | window.name | +| react-use-router.js:5:9:5:28 | router | react-use-router.js:9:21:9:26 | router | +| react-use-router.js:5:18:5:28 | useRouter() | react-use-router.js:5:9:5:28 | router | +| react-use-router.js:9:21:9:26 | router | react-use-router.js:9:21:9:32 | router.query | +| react-use-router.js:9:21:9:32 | router.query | react-use-router.js:9:21:9:39 | router.query.foobar | +| react-use-router.js:9:21:9:32 | router.query | react-use-router.js:9:21:9:39 | router.query.foobar | +| react-use-router.js:9:21:9:32 | router.query | react-use-router.js:9:21:9:39 | router.query.foobar | +| react-use-router.js:9:21:9:32 | router.query | react-use-router.js:9:21:9:39 | router.query.foobar | +| react-use-router.js:9:21:9:39 | router.query.foobar | react-use-router.js:5:18:5:28 | useRouter() | +| react-use-router.js:20:15:20:24 | router | react-use-router.js:21:43:21:48 | router | +| react-use-router.js:20:17:20:22 | router | react-use-router.js:20:15:20:24 | router | +| react-use-router.js:21:43:21:48 | router | react-use-router.js:21:43:21:54 | router.query | +| react-use-router.js:21:43:21:54 | router.query | react-use-router.js:21:43:21:61 | router.query.foobar | +| react-use-router.js:21:43:21:54 | router.query | react-use-router.js:21:43:21:61 | router.query.foobar | +| react-use-router.js:21:43:21:54 | router.query | react-use-router.js:21:43:21:61 | router.query.foobar | +| react-use-router.js:21:43:21:54 | router.query | react-use-router.js:21:43:21:61 | router.query.foobar | +| react-use-router.js:21:43:21:61 | router.query.foobar | react-use-router.js:20:17:20:22 | router | | react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state | | react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state | | react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/react-use-router.js b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/react-use-router.js new file mode 100644 index 000000000000..674f812467ca --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/react-use-router.js @@ -0,0 +1,23 @@ + +import { useRouter } from 'next/router' + +export function nextRouter() { + const router = useRouter(); + return ( +
+ { + router.push(router.query.foobar) // NOT OK + }}>Click to XSS 1 + { + router.push('/?foobar=' + router.query.foobar) // OK + }}>Safe Link +
+ ) +} + +import { withRouter } from 'next/router' + +function Page({ router }) { + return router.push(router.query.foobar)}>Click to XSS 2 // NOT OK +} +export const pageWithRouter = withRouter(Page); From 668e1accaae91847ebaf9b68534cad0793b9bb9b Mon Sep 17 00:00:00 2001 From: tyage Date: Sat, 8 Apr 2023 18:24:31 +0900 Subject: [PATCH 2/4] Remove unnecessary whiteline --- .../Security/CWE-079/DomBasedXss/Xss.expected | 64 +++++++++---------- .../XssWithAdditionalSources.expected | 60 ++++++++--------- .../CWE-079/DomBasedXss/react-use-router.js | 1 - 3 files changed, 62 insertions(+), 63 deletions(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected index ddf5bbb51b27..39b698b2f0a6 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected @@ -560,20 +560,20 @@ nodes | react-use-context.js:16:26:16:36 | window.name | | react-use-context.js:16:26:16:36 | window.name | | react-use-context.js:16:26:16:36 | window.name | -| react-use-router.js:5:9:5:28 | router | -| react-use-router.js:5:18:5:28 | useRouter() | -| react-use-router.js:9:21:9:26 | router | -| react-use-router.js:9:21:9:32 | router.query | -| react-use-router.js:9:21:9:32 | router.query | -| react-use-router.js:9:21:9:39 | router.query.foobar | -| react-use-router.js:9:21:9:39 | router.query.foobar | -| react-use-router.js:20:15:20:24 | router | -| react-use-router.js:20:17:20:22 | router | -| react-use-router.js:21:43:21:48 | router | -| react-use-router.js:21:43:21:54 | router.query | -| react-use-router.js:21:43:21:54 | router.query | -| react-use-router.js:21:43:21:61 | router.query.foobar | -| react-use-router.js:21:43:21:61 | router.query.foobar | +| react-use-router.js:4:9:4:28 | router | +| react-use-router.js:4:18:4:28 | useRouter() | +| react-use-router.js:8:21:8:26 | router | +| react-use-router.js:8:21:8:32 | router.query | +| react-use-router.js:8:21:8:32 | router.query | +| react-use-router.js:8:21:8:39 | router.query.foobar | +| react-use-router.js:8:21:8:39 | router.query.foobar | +| react-use-router.js:19:15:19:24 | router | +| react-use-router.js:19:17:19:22 | router | +| react-use-router.js:20:43:20:48 | router | +| react-use-router.js:20:43:20:54 | router.query | +| react-use-router.js:20:43:20:54 | router.query | +| react-use-router.js:20:43:20:61 | router.query.foobar | +| react-use-router.js:20:43:20:61 | router.query.foobar | | react-use-state.js:4:9:4:49 | state | | react-use-state.js:4:9:4:49 | state | | react-use-state.js:4:10:4:14 | state | @@ -1714,22 +1714,22 @@ edges | react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted | | react-use-context.js:10:22:10:32 | window.name | react-use-context.js:10:22:10:32 | window.name | | react-use-context.js:16:26:16:36 | window.name | react-use-context.js:16:26:16:36 | window.name | -| react-use-router.js:5:9:5:28 | router | react-use-router.js:9:21:9:26 | router | -| react-use-router.js:5:18:5:28 | useRouter() | react-use-router.js:5:9:5:28 | router | -| react-use-router.js:9:21:9:26 | router | react-use-router.js:9:21:9:32 | router.query | -| react-use-router.js:9:21:9:32 | router.query | react-use-router.js:9:21:9:39 | router.query.foobar | -| react-use-router.js:9:21:9:32 | router.query | react-use-router.js:9:21:9:39 | router.query.foobar | -| react-use-router.js:9:21:9:32 | router.query | react-use-router.js:9:21:9:39 | router.query.foobar | -| react-use-router.js:9:21:9:32 | router.query | react-use-router.js:9:21:9:39 | router.query.foobar | -| react-use-router.js:9:21:9:39 | router.query.foobar | react-use-router.js:5:18:5:28 | useRouter() | -| react-use-router.js:20:15:20:24 | router | react-use-router.js:21:43:21:48 | router | -| react-use-router.js:20:17:20:22 | router | react-use-router.js:20:15:20:24 | router | -| react-use-router.js:21:43:21:48 | router | react-use-router.js:21:43:21:54 | router.query | -| react-use-router.js:21:43:21:54 | router.query | react-use-router.js:21:43:21:61 | router.query.foobar | -| react-use-router.js:21:43:21:54 | router.query | react-use-router.js:21:43:21:61 | router.query.foobar | -| react-use-router.js:21:43:21:54 | router.query | react-use-router.js:21:43:21:61 | router.query.foobar | -| react-use-router.js:21:43:21:54 | router.query | react-use-router.js:21:43:21:61 | router.query.foobar | -| react-use-router.js:21:43:21:61 | router.query.foobar | react-use-router.js:20:17:20:22 | router | +| react-use-router.js:4:9:4:28 | router | react-use-router.js:8:21:8:26 | router | +| react-use-router.js:4:18:4:28 | useRouter() | react-use-router.js:4:9:4:28 | router | +| react-use-router.js:8:21:8:26 | router | react-use-router.js:8:21:8:32 | router.query | +| react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar | +| react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar | +| react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar | +| react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar | +| react-use-router.js:8:21:8:39 | router.query.foobar | react-use-router.js:4:18:4:28 | useRouter() | +| react-use-router.js:19:15:19:24 | router | react-use-router.js:20:43:20:48 | router | +| react-use-router.js:19:17:19:22 | router | react-use-router.js:19:15:19:24 | router | +| react-use-router.js:20:43:20:48 | router | react-use-router.js:20:43:20:54 | router.query | +| react-use-router.js:20:43:20:54 | router.query | react-use-router.js:20:43:20:61 | router.query.foobar | +| react-use-router.js:20:43:20:54 | router.query | react-use-router.js:20:43:20:61 | router.query.foobar | +| react-use-router.js:20:43:20:54 | router.query | react-use-router.js:20:43:20:61 | router.query.foobar | +| react-use-router.js:20:43:20:54 | router.query | react-use-router.js:20:43:20:61 | router.query.foobar | +| react-use-router.js:20:43:20:61 | router.query.foobar | react-use-router.js:19:17:19:22 | router | | react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state | | react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state | | react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state | @@ -2416,8 +2416,8 @@ edges | react-native.js:9:27:9:33 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:9:27:9:33 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value | | react-use-context.js:10:22:10:32 | window.name | react-use-context.js:10:22:10:32 | window.name | react-use-context.js:10:22:10:32 | window.name | Cross-site scripting vulnerability due to $@. | react-use-context.js:10:22:10:32 | window.name | user-provided value | | react-use-context.js:16:26:16:36 | window.name | react-use-context.js:16:26:16:36 | window.name | react-use-context.js:16:26:16:36 | window.name | Cross-site scripting vulnerability due to $@. | react-use-context.js:16:26:16:36 | window.name | user-provided value | -| react-use-router.js:9:21:9:39 | router.query.foobar | react-use-router.js:9:21:9:32 | router.query | react-use-router.js:9:21:9:39 | router.query.foobar | Cross-site scripting vulnerability due to $@. | react-use-router.js:9:21:9:32 | router.query | user-provided value | -| react-use-router.js:21:43:21:61 | router.query.foobar | react-use-router.js:21:43:21:54 | router.query | react-use-router.js:21:43:21:61 | router.query.foobar | Cross-site scripting vulnerability due to $@. | react-use-router.js:21:43:21:54 | router.query | user-provided value | +| react-use-router.js:8:21:8:39 | router.query.foobar | react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar | Cross-site scripting vulnerability due to $@. | react-use-router.js:8:21:8:32 | router.query | user-provided value | +| react-use-router.js:20:43:20:61 | router.query.foobar | react-use-router.js:20:43:20:54 | router.query | react-use-router.js:20:43:20:61 | router.query.foobar | Cross-site scripting vulnerability due to $@. | react-use-router.js:20:43:20:54 | router.query | user-provided value | | react-use-state.js:5:51:5:55 | state | react-use-state.js:4:38:4:48 | window.name | react-use-state.js:5:51:5:55 | state | Cross-site scripting vulnerability due to $@. | react-use-state.js:4:38:4:48 | window.name | user-provided value | | react-use-state.js:11:51:11:55 | state | react-use-state.js:10:14:10:24 | window.name | react-use-state.js:11:51:11:55 | state | Cross-site scripting vulnerability due to $@. | react-use-state.js:10:14:10:24 | window.name | user-provided value | | react-use-state.js:17:51:17:55 | state | react-use-state.js:16:20:16:30 | window.name | react-use-state.js:17:51:17:55 | state | Cross-site scripting vulnerability due to $@. | react-use-state.js:16:20:16:30 | window.name | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected index e9b676b4a272..712009eb2ddd 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected @@ -572,20 +572,20 @@ nodes | react-use-context.js:16:26:16:36 | window.name | | react-use-context.js:16:26:16:36 | window.name | | react-use-context.js:16:26:16:36 | window.name | -| react-use-router.js:5:9:5:28 | router | -| react-use-router.js:5:18:5:28 | useRouter() | -| react-use-router.js:9:21:9:26 | router | -| react-use-router.js:9:21:9:32 | router.query | -| react-use-router.js:9:21:9:32 | router.query | -| react-use-router.js:9:21:9:39 | router.query.foobar | -| react-use-router.js:9:21:9:39 | router.query.foobar | -| react-use-router.js:20:15:20:24 | router | -| react-use-router.js:20:17:20:22 | router | -| react-use-router.js:21:43:21:48 | router | -| react-use-router.js:21:43:21:54 | router.query | -| react-use-router.js:21:43:21:54 | router.query | -| react-use-router.js:21:43:21:61 | router.query.foobar | -| react-use-router.js:21:43:21:61 | router.query.foobar | +| react-use-router.js:4:9:4:28 | router | +| react-use-router.js:4:18:4:28 | useRouter() | +| react-use-router.js:8:21:8:26 | router | +| react-use-router.js:8:21:8:32 | router.query | +| react-use-router.js:8:21:8:32 | router.query | +| react-use-router.js:8:21:8:39 | router.query.foobar | +| react-use-router.js:8:21:8:39 | router.query.foobar | +| react-use-router.js:19:15:19:24 | router | +| react-use-router.js:19:17:19:22 | router | +| react-use-router.js:20:43:20:48 | router | +| react-use-router.js:20:43:20:54 | router.query | +| react-use-router.js:20:43:20:54 | router.query | +| react-use-router.js:20:43:20:61 | router.query.foobar | +| react-use-router.js:20:43:20:61 | router.query.foobar | | react-use-state.js:4:9:4:49 | state | | react-use-state.js:4:9:4:49 | state | | react-use-state.js:4:10:4:14 | state | @@ -1776,22 +1776,22 @@ edges | react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted | | react-use-context.js:10:22:10:32 | window.name | react-use-context.js:10:22:10:32 | window.name | | react-use-context.js:16:26:16:36 | window.name | react-use-context.js:16:26:16:36 | window.name | -| react-use-router.js:5:9:5:28 | router | react-use-router.js:9:21:9:26 | router | -| react-use-router.js:5:18:5:28 | useRouter() | react-use-router.js:5:9:5:28 | router | -| react-use-router.js:9:21:9:26 | router | react-use-router.js:9:21:9:32 | router.query | -| react-use-router.js:9:21:9:32 | router.query | react-use-router.js:9:21:9:39 | router.query.foobar | -| react-use-router.js:9:21:9:32 | router.query | react-use-router.js:9:21:9:39 | router.query.foobar | -| react-use-router.js:9:21:9:32 | router.query | react-use-router.js:9:21:9:39 | router.query.foobar | -| react-use-router.js:9:21:9:32 | router.query | react-use-router.js:9:21:9:39 | router.query.foobar | -| react-use-router.js:9:21:9:39 | router.query.foobar | react-use-router.js:5:18:5:28 | useRouter() | -| react-use-router.js:20:15:20:24 | router | react-use-router.js:21:43:21:48 | router | -| react-use-router.js:20:17:20:22 | router | react-use-router.js:20:15:20:24 | router | -| react-use-router.js:21:43:21:48 | router | react-use-router.js:21:43:21:54 | router.query | -| react-use-router.js:21:43:21:54 | router.query | react-use-router.js:21:43:21:61 | router.query.foobar | -| react-use-router.js:21:43:21:54 | router.query | react-use-router.js:21:43:21:61 | router.query.foobar | -| react-use-router.js:21:43:21:54 | router.query | react-use-router.js:21:43:21:61 | router.query.foobar | -| react-use-router.js:21:43:21:54 | router.query | react-use-router.js:21:43:21:61 | router.query.foobar | -| react-use-router.js:21:43:21:61 | router.query.foobar | react-use-router.js:20:17:20:22 | router | +| react-use-router.js:4:9:4:28 | router | react-use-router.js:8:21:8:26 | router | +| react-use-router.js:4:18:4:28 | useRouter() | react-use-router.js:4:9:4:28 | router | +| react-use-router.js:8:21:8:26 | router | react-use-router.js:8:21:8:32 | router.query | +| react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar | +| react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar | +| react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar | +| react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar | +| react-use-router.js:8:21:8:39 | router.query.foobar | react-use-router.js:4:18:4:28 | useRouter() | +| react-use-router.js:19:15:19:24 | router | react-use-router.js:20:43:20:48 | router | +| react-use-router.js:19:17:19:22 | router | react-use-router.js:19:15:19:24 | router | +| react-use-router.js:20:43:20:48 | router | react-use-router.js:20:43:20:54 | router.query | +| react-use-router.js:20:43:20:54 | router.query | react-use-router.js:20:43:20:61 | router.query.foobar | +| react-use-router.js:20:43:20:54 | router.query | react-use-router.js:20:43:20:61 | router.query.foobar | +| react-use-router.js:20:43:20:54 | router.query | react-use-router.js:20:43:20:61 | router.query.foobar | +| react-use-router.js:20:43:20:54 | router.query | react-use-router.js:20:43:20:61 | router.query.foobar | +| react-use-router.js:20:43:20:61 | router.query.foobar | react-use-router.js:19:17:19:22 | router | | react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state | | react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state | | react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/react-use-router.js b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/react-use-router.js index 674f812467ca..6128eef4648b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/react-use-router.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/react-use-router.js @@ -1,4 +1,3 @@ - import { useRouter } from 'next/router' export function nextRouter() { From 320cb99dbfb118211657d10ff33c85fc160ba3e1 Mon Sep 17 00:00:00 2001 From: tyage Date: Sat, 8 Apr 2023 18:31:48 +0900 Subject: [PATCH 3/4] Add replace method test --- .../Security/CWE-079/DomBasedXss/Xss.expected | 45 ++++++++++++------- .../XssWithAdditionalSources.expected | 41 ++++++++++------- .../CWE-079/DomBasedXss/react-use-router.js | 5 ++- 3 files changed, 59 insertions(+), 32 deletions(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected index 39b698b2f0a6..383f0a8f5808 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected @@ -567,13 +567,18 @@ nodes | react-use-router.js:8:21:8:32 | router.query | | react-use-router.js:8:21:8:39 | router.query.foobar | | react-use-router.js:8:21:8:39 | router.query.foobar | -| react-use-router.js:19:15:19:24 | router | -| react-use-router.js:19:17:19:22 | router | -| react-use-router.js:20:43:20:48 | router | -| react-use-router.js:20:43:20:54 | router.query | -| react-use-router.js:20:43:20:54 | router.query | -| react-use-router.js:20:43:20:61 | router.query.foobar | -| react-use-router.js:20:43:20:61 | router.query.foobar | +| react-use-router.js:11:24:11:29 | router | +| react-use-router.js:11:24:11:35 | router.query | +| react-use-router.js:11:24:11:35 | router.query | +| react-use-router.js:11:24:11:42 | router.query.foobar | +| react-use-router.js:11:24:11:42 | router.query.foobar | +| react-use-router.js:22:15:22:24 | router | +| react-use-router.js:22:17:22:22 | router | +| react-use-router.js:23:43:23:48 | router | +| react-use-router.js:23:43:23:54 | router.query | +| react-use-router.js:23:43:23:54 | router.query | +| react-use-router.js:23:43:23:61 | router.query.foobar | +| react-use-router.js:23:43:23:61 | router.query.foobar | | react-use-state.js:4:9:4:49 | state | | react-use-state.js:4:9:4:49 | state | | react-use-state.js:4:10:4:14 | state | @@ -1715,6 +1720,7 @@ edges | react-use-context.js:10:22:10:32 | window.name | react-use-context.js:10:22:10:32 | window.name | | react-use-context.js:16:26:16:36 | window.name | react-use-context.js:16:26:16:36 | window.name | | react-use-router.js:4:9:4:28 | router | react-use-router.js:8:21:8:26 | router | +| react-use-router.js:4:9:4:28 | router | react-use-router.js:11:24:11:29 | router | | react-use-router.js:4:18:4:28 | useRouter() | react-use-router.js:4:9:4:28 | router | | react-use-router.js:8:21:8:26 | router | react-use-router.js:8:21:8:32 | router.query | | react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar | @@ -1722,14 +1728,19 @@ edges | react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar | | react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar | | react-use-router.js:8:21:8:39 | router.query.foobar | react-use-router.js:4:18:4:28 | useRouter() | -| react-use-router.js:19:15:19:24 | router | react-use-router.js:20:43:20:48 | router | -| react-use-router.js:19:17:19:22 | router | react-use-router.js:19:15:19:24 | router | -| react-use-router.js:20:43:20:48 | router | react-use-router.js:20:43:20:54 | router.query | -| react-use-router.js:20:43:20:54 | router.query | react-use-router.js:20:43:20:61 | router.query.foobar | -| react-use-router.js:20:43:20:54 | router.query | react-use-router.js:20:43:20:61 | router.query.foobar | -| react-use-router.js:20:43:20:54 | router.query | react-use-router.js:20:43:20:61 | router.query.foobar | -| react-use-router.js:20:43:20:54 | router.query | react-use-router.js:20:43:20:61 | router.query.foobar | -| react-use-router.js:20:43:20:61 | router.query.foobar | react-use-router.js:19:17:19:22 | router | +| react-use-router.js:11:24:11:29 | router | react-use-router.js:11:24:11:35 | router.query | +| react-use-router.js:11:24:11:35 | router.query | react-use-router.js:11:24:11:42 | router.query.foobar | +| react-use-router.js:11:24:11:35 | router.query | react-use-router.js:11:24:11:42 | router.query.foobar | +| react-use-router.js:11:24:11:35 | router.query | react-use-router.js:11:24:11:42 | router.query.foobar | +| react-use-router.js:11:24:11:35 | router.query | react-use-router.js:11:24:11:42 | router.query.foobar | +| react-use-router.js:22:15:22:24 | router | react-use-router.js:23:43:23:48 | router | +| react-use-router.js:22:17:22:22 | router | react-use-router.js:22:15:22:24 | router | +| react-use-router.js:23:43:23:48 | router | react-use-router.js:23:43:23:54 | router.query | +| react-use-router.js:23:43:23:54 | router.query | react-use-router.js:23:43:23:61 | router.query.foobar | +| react-use-router.js:23:43:23:54 | router.query | react-use-router.js:23:43:23:61 | router.query.foobar | +| react-use-router.js:23:43:23:54 | router.query | react-use-router.js:23:43:23:61 | router.query.foobar | +| react-use-router.js:23:43:23:54 | router.query | react-use-router.js:23:43:23:61 | router.query.foobar | +| react-use-router.js:23:43:23:61 | router.query.foobar | react-use-router.js:22:17:22:22 | router | | react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state | | react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state | | react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state | @@ -2417,7 +2428,9 @@ edges | react-use-context.js:10:22:10:32 | window.name | react-use-context.js:10:22:10:32 | window.name | react-use-context.js:10:22:10:32 | window.name | Cross-site scripting vulnerability due to $@. | react-use-context.js:10:22:10:32 | window.name | user-provided value | | react-use-context.js:16:26:16:36 | window.name | react-use-context.js:16:26:16:36 | window.name | react-use-context.js:16:26:16:36 | window.name | Cross-site scripting vulnerability due to $@. | react-use-context.js:16:26:16:36 | window.name | user-provided value | | react-use-router.js:8:21:8:39 | router.query.foobar | react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar | Cross-site scripting vulnerability due to $@. | react-use-router.js:8:21:8:32 | router.query | user-provided value | -| react-use-router.js:20:43:20:61 | router.query.foobar | react-use-router.js:20:43:20:54 | router.query | react-use-router.js:20:43:20:61 | router.query.foobar | Cross-site scripting vulnerability due to $@. | react-use-router.js:20:43:20:54 | router.query | user-provided value | +| react-use-router.js:11:24:11:42 | router.query.foobar | react-use-router.js:8:21:8:32 | router.query | react-use-router.js:11:24:11:42 | router.query.foobar | Cross-site scripting vulnerability due to $@. | react-use-router.js:8:21:8:32 | router.query | user-provided value | +| react-use-router.js:11:24:11:42 | router.query.foobar | react-use-router.js:11:24:11:35 | router.query | react-use-router.js:11:24:11:42 | router.query.foobar | Cross-site scripting vulnerability due to $@. | react-use-router.js:11:24:11:35 | router.query | user-provided value | +| react-use-router.js:23:43:23:61 | router.query.foobar | react-use-router.js:23:43:23:54 | router.query | react-use-router.js:23:43:23:61 | router.query.foobar | Cross-site scripting vulnerability due to $@. | react-use-router.js:23:43:23:54 | router.query | user-provided value | | react-use-state.js:5:51:5:55 | state | react-use-state.js:4:38:4:48 | window.name | react-use-state.js:5:51:5:55 | state | Cross-site scripting vulnerability due to $@. | react-use-state.js:4:38:4:48 | window.name | user-provided value | | react-use-state.js:11:51:11:55 | state | react-use-state.js:10:14:10:24 | window.name | react-use-state.js:11:51:11:55 | state | Cross-site scripting vulnerability due to $@. | react-use-state.js:10:14:10:24 | window.name | user-provided value | | react-use-state.js:17:51:17:55 | state | react-use-state.js:16:20:16:30 | window.name | react-use-state.js:17:51:17:55 | state | Cross-site scripting vulnerability due to $@. | react-use-state.js:16:20:16:30 | window.name | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected index 712009eb2ddd..5dbee3f5b438 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected @@ -579,13 +579,18 @@ nodes | react-use-router.js:8:21:8:32 | router.query | | react-use-router.js:8:21:8:39 | router.query.foobar | | react-use-router.js:8:21:8:39 | router.query.foobar | -| react-use-router.js:19:15:19:24 | router | -| react-use-router.js:19:17:19:22 | router | -| react-use-router.js:20:43:20:48 | router | -| react-use-router.js:20:43:20:54 | router.query | -| react-use-router.js:20:43:20:54 | router.query | -| react-use-router.js:20:43:20:61 | router.query.foobar | -| react-use-router.js:20:43:20:61 | router.query.foobar | +| react-use-router.js:11:24:11:29 | router | +| react-use-router.js:11:24:11:35 | router.query | +| react-use-router.js:11:24:11:35 | router.query | +| react-use-router.js:11:24:11:42 | router.query.foobar | +| react-use-router.js:11:24:11:42 | router.query.foobar | +| react-use-router.js:22:15:22:24 | router | +| react-use-router.js:22:17:22:22 | router | +| react-use-router.js:23:43:23:48 | router | +| react-use-router.js:23:43:23:54 | router.query | +| react-use-router.js:23:43:23:54 | router.query | +| react-use-router.js:23:43:23:61 | router.query.foobar | +| react-use-router.js:23:43:23:61 | router.query.foobar | | react-use-state.js:4:9:4:49 | state | | react-use-state.js:4:9:4:49 | state | | react-use-state.js:4:10:4:14 | state | @@ -1777,6 +1782,7 @@ edges | react-use-context.js:10:22:10:32 | window.name | react-use-context.js:10:22:10:32 | window.name | | react-use-context.js:16:26:16:36 | window.name | react-use-context.js:16:26:16:36 | window.name | | react-use-router.js:4:9:4:28 | router | react-use-router.js:8:21:8:26 | router | +| react-use-router.js:4:9:4:28 | router | react-use-router.js:11:24:11:29 | router | | react-use-router.js:4:18:4:28 | useRouter() | react-use-router.js:4:9:4:28 | router | | react-use-router.js:8:21:8:26 | router | react-use-router.js:8:21:8:32 | router.query | | react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar | @@ -1784,14 +1790,19 @@ edges | react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar | | react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar | | react-use-router.js:8:21:8:39 | router.query.foobar | react-use-router.js:4:18:4:28 | useRouter() | -| react-use-router.js:19:15:19:24 | router | react-use-router.js:20:43:20:48 | router | -| react-use-router.js:19:17:19:22 | router | react-use-router.js:19:15:19:24 | router | -| react-use-router.js:20:43:20:48 | router | react-use-router.js:20:43:20:54 | router.query | -| react-use-router.js:20:43:20:54 | router.query | react-use-router.js:20:43:20:61 | router.query.foobar | -| react-use-router.js:20:43:20:54 | router.query | react-use-router.js:20:43:20:61 | router.query.foobar | -| react-use-router.js:20:43:20:54 | router.query | react-use-router.js:20:43:20:61 | router.query.foobar | -| react-use-router.js:20:43:20:54 | router.query | react-use-router.js:20:43:20:61 | router.query.foobar | -| react-use-router.js:20:43:20:61 | router.query.foobar | react-use-router.js:19:17:19:22 | router | +| react-use-router.js:11:24:11:29 | router | react-use-router.js:11:24:11:35 | router.query | +| react-use-router.js:11:24:11:35 | router.query | react-use-router.js:11:24:11:42 | router.query.foobar | +| react-use-router.js:11:24:11:35 | router.query | react-use-router.js:11:24:11:42 | router.query.foobar | +| react-use-router.js:11:24:11:35 | router.query | react-use-router.js:11:24:11:42 | router.query.foobar | +| react-use-router.js:11:24:11:35 | router.query | react-use-router.js:11:24:11:42 | router.query.foobar | +| react-use-router.js:22:15:22:24 | router | react-use-router.js:23:43:23:48 | router | +| react-use-router.js:22:17:22:22 | router | react-use-router.js:22:15:22:24 | router | +| react-use-router.js:23:43:23:48 | router | react-use-router.js:23:43:23:54 | router.query | +| react-use-router.js:23:43:23:54 | router.query | react-use-router.js:23:43:23:61 | router.query.foobar | +| react-use-router.js:23:43:23:54 | router.query | react-use-router.js:23:43:23:61 | router.query.foobar | +| react-use-router.js:23:43:23:54 | router.query | react-use-router.js:23:43:23:61 | router.query.foobar | +| react-use-router.js:23:43:23:54 | router.query | react-use-router.js:23:43:23:61 | router.query.foobar | +| react-use-router.js:23:43:23:61 | router.query.foobar | react-use-router.js:22:17:22:22 | router | | react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state | | react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state | | react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/react-use-router.js b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/react-use-router.js index 6128eef4648b..321821cd7291 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/react-use-router.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/react-use-router.js @@ -7,6 +7,9 @@ export function nextRouter() { { router.push(router.query.foobar) // NOT OK }}>Click to XSS 1 + { + router.replace(router.query.foobar) // NOT OK + }}>Click to XSS 2 { router.push('/?foobar=' + router.query.foobar) // OK }}>Safe Link @@ -17,6 +20,6 @@ export function nextRouter() { import { withRouter } from 'next/router' function Page({ router }) { - return router.push(router.query.foobar)}>Click to XSS 2 // NOT OK + return router.push(router.query.foobar)}>Click to XSS 3 // NOT OK } export const pageWithRouter = withRouter(Page); From 40d475863d034048d911c3124c3ce34115caa5ae Mon Sep 17 00:00:00 2001 From: tyage Date: Sat, 8 Apr 2023 18:36:50 +0900 Subject: [PATCH 4/4] Add change note --- .../ql/lib/change-notes/2023-04-08-NextJS-router-push.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 javascript/ql/lib/change-notes/2023-04-08-NextJS-router-push.md diff --git a/javascript/ql/lib/change-notes/2023-04-08-NextJS-router-push.md b/javascript/ql/lib/change-notes/2023-04-08-NextJS-router-push.md new file mode 100644 index 000000000000..83547b0bf5a9 --- /dev/null +++ b/javascript/ql/lib/change-notes/2023-04-08-NextJS-router-push.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* `router.push` and `router.replace` in `Next.js` are now considered as XSS sink.