Skip to content

Commit cecb498

Browse files
authored
Merge pull request github#10984 from tyage/add-next-js-source
JS: Add Next.js parameters as source
2 parents 71f29f0 + c22f944 commit cecb498

File tree

6 files changed

+184
-1
lines changed

6 files changed

+184
-1
lines changed

javascript/ql/lib/semmle/javascript/frameworks/Next.qll

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ module NextJS {
4343
}
4444

4545
/**
46-
* A user defined path parameter in `Next.js`.
46+
* A user defined path or query parameter in `Next.js`.
4747
*/
4848
class NextParams extends RemoteFlowSource {
4949
NextParams() {
@@ -53,6 +53,10 @@ module NextJS {
5353
.getAFunctionValue()
5454
.getParameter(0)
5555
.getAPropertyRead("params")
56+
or
57+
this = getServerSidePropsFunction(_).getParameter(0).getAPropertyRead(["params", "query"])
58+
or
59+
this = nextRouter().getAPropertyRead("query")
5660
}
5761

5862
override string getSourceType() { result = "Next request parameter" }
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
5+
- Added sources for user defined path and query parameters in `Next.js`.

javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,38 @@ nodes
504504
| optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) |
505505
| optionalSanitizer.js:45:41:45:46 | target |
506506
| optionalSanitizer.js:45:51:45:56 | target |
507+
| pages/[id].jsx:5:9:5:14 | { id } |
508+
| pages/[id].jsx:5:9:5:14 | { id } |
509+
| pages/[id].jsx:5:9:5:29 | id |
510+
| pages/[id].jsx:5:9:5:29 | id |
511+
| pages/[id].jsx:5:11:5:12 | id |
512+
| pages/[id].jsx:5:11:5:12 | id |
513+
| pages/[id].jsx:5:18:5:29 | router.query |
514+
| pages/[id].jsx:5:18:5:29 | router.query |
515+
| pages/[id].jsx:5:18:5:29 | router.query |
516+
| pages/[id].jsx:10:44:10:45 | id |
517+
| pages/[id].jsx:10:44:10:45 | id |
518+
| pages/[id].jsx:10:44:10:45 | id |
519+
| pages/[id].jsx:13:44:13:52 | params.id |
520+
| pages/[id].jsx:13:44:13:52 | params.id |
521+
| pages/[id].jsx:13:44:13:52 | params.id |
522+
| pages/[id].jsx:16:44:16:51 | params.q |
523+
| pages/[id].jsx:16:44:16:51 | params.q |
524+
| pages/[id].jsx:16:44:16:51 | params.q |
525+
| pages/[id].jsx:25:11:25:24 | context.params |
526+
| pages/[id].jsx:25:11:25:24 | context.params |
527+
| pages/[id].jsx:25:11:25:24 | context.params |
528+
| pages/[id].jsx:25:11:25:27 | context.params.id |
529+
| pages/[id].jsx:25:11:25:27 | context.params.id |
530+
| pages/[id].jsx:25:11:25:33 | context ... d \|\| "" |
531+
| pages/[id].jsx:25:11:25:33 | context ... d \|\| "" |
532+
| pages/[id].jsx:26:10:26:22 | context.query |
533+
| pages/[id].jsx:26:10:26:22 | context.query |
534+
| pages/[id].jsx:26:10:26:22 | context.query |
535+
| pages/[id].jsx:26:10:26:30 | context ... .foobar |
536+
| pages/[id].jsx:26:10:26:30 | context ... .foobar |
537+
| pages/[id].jsx:26:10:26:36 | context ... r \|\| "" |
538+
| pages/[id].jsx:26:10:26:36 | context ... r \|\| "" |
507539
| react-native.js:7:7:7:33 | tainted |
508540
| react-native.js:7:7:7:33 | tainted |
509541
| react-native.js:7:17:7:33 | req.param("code") |
@@ -1604,6 +1636,38 @@ edges
16041636
| optionalSanitizer.js:45:41:45:46 | target | optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) |
16051637
| optionalSanitizer.js:45:51:45:56 | target | optionalSanitizer.js:45:18:45:56 | sanitiz ... target |
16061638
| optionalSanitizer.js:45:51:45:56 | target | optionalSanitizer.js:45:18:45:56 | sanitiz ... target |
1639+
| pages/[id].jsx:5:9:5:14 | { id } | pages/[id].jsx:5:11:5:12 | id |
1640+
| pages/[id].jsx:5:9:5:14 | { id } | pages/[id].jsx:5:11:5:12 | id |
1641+
| pages/[id].jsx:5:9:5:29 | id | pages/[id].jsx:10:44:10:45 | id |
1642+
| pages/[id].jsx:5:9:5:29 | id | pages/[id].jsx:10:44:10:45 | id |
1643+
| pages/[id].jsx:5:9:5:29 | id | pages/[id].jsx:10:44:10:45 | id |
1644+
| pages/[id].jsx:5:9:5:29 | id | pages/[id].jsx:10:44:10:45 | id |
1645+
| pages/[id].jsx:5:11:5:12 | id | pages/[id].jsx:5:9:5:29 | id |
1646+
| pages/[id].jsx:5:11:5:12 | id | pages/[id].jsx:5:9:5:29 | id |
1647+
| pages/[id].jsx:5:18:5:29 | router.query | pages/[id].jsx:5:9:5:14 | { id } |
1648+
| pages/[id].jsx:5:18:5:29 | router.query | pages/[id].jsx:5:9:5:14 | { id } |
1649+
| pages/[id].jsx:5:18:5:29 | router.query | pages/[id].jsx:5:9:5:14 | { id } |
1650+
| pages/[id].jsx:5:18:5:29 | router.query | pages/[id].jsx:5:9:5:14 | { id } |
1651+
| pages/[id].jsx:25:11:25:24 | context.params | pages/[id].jsx:25:11:25:27 | context.params.id |
1652+
| pages/[id].jsx:25:11:25:24 | context.params | pages/[id].jsx:25:11:25:27 | context.params.id |
1653+
| pages/[id].jsx:25:11:25:24 | context.params | pages/[id].jsx:25:11:25:27 | context.params.id |
1654+
| pages/[id].jsx:25:11:25:24 | context.params | pages/[id].jsx:25:11:25:27 | context.params.id |
1655+
| pages/[id].jsx:25:11:25:27 | context.params.id | pages/[id].jsx:25:11:25:33 | context ... d \|\| "" |
1656+
| pages/[id].jsx:25:11:25:27 | context.params.id | pages/[id].jsx:25:11:25:33 | context ... d \|\| "" |
1657+
| pages/[id].jsx:25:11:25:33 | context ... d \|\| "" | pages/[id].jsx:13:44:13:52 | params.id |
1658+
| pages/[id].jsx:25:11:25:33 | context ... d \|\| "" | pages/[id].jsx:13:44:13:52 | params.id |
1659+
| pages/[id].jsx:25:11:25:33 | context ... d \|\| "" | pages/[id].jsx:13:44:13:52 | params.id |
1660+
| pages/[id].jsx:25:11:25:33 | context ... d \|\| "" | pages/[id].jsx:13:44:13:52 | params.id |
1661+
| pages/[id].jsx:26:10:26:22 | context.query | pages/[id].jsx:26:10:26:30 | context ... .foobar |
1662+
| pages/[id].jsx:26:10:26:22 | context.query | pages/[id].jsx:26:10:26:30 | context ... .foobar |
1663+
| pages/[id].jsx:26:10:26:22 | context.query | pages/[id].jsx:26:10:26:30 | context ... .foobar |
1664+
| pages/[id].jsx:26:10:26:22 | context.query | pages/[id].jsx:26:10:26:30 | context ... .foobar |
1665+
| pages/[id].jsx:26:10:26:30 | context ... .foobar | pages/[id].jsx:26:10:26:36 | context ... r \|\| "" |
1666+
| pages/[id].jsx:26:10:26:30 | context ... .foobar | pages/[id].jsx:26:10:26:36 | context ... r \|\| "" |
1667+
| pages/[id].jsx:26:10:26:36 | context ... r \|\| "" | pages/[id].jsx:16:44:16:51 | params.q |
1668+
| pages/[id].jsx:26:10:26:36 | context ... r \|\| "" | pages/[id].jsx:16:44:16:51 | params.q |
1669+
| pages/[id].jsx:26:10:26:36 | context ... r \|\| "" | pages/[id].jsx:16:44:16:51 | params.q |
1670+
| pages/[id].jsx:26:10:26:36 | context ... r \|\| "" | pages/[id].jsx:16:44:16:51 | params.q |
16071671
| react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted |
16081672
| react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted |
16091673
| react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted |
@@ -2287,6 +2351,9 @@ edges
22872351
| optionalSanitizer.js:39:18:39:25 | tainted3 | optionalSanitizer.js:26:16:26:39 | documen ... .search | optionalSanitizer.js:39:18:39:25 | tainted3 | Cross-site scripting vulnerability due to $@. | optionalSanitizer.js:26:16:26:39 | documen ... .search | user-provided value |
22882352
| optionalSanitizer.js:43:18:43:25 | tainted3 | optionalSanitizer.js:26:16:26:39 | documen ... .search | optionalSanitizer.js:43:18:43:25 | tainted3 | Cross-site scripting vulnerability due to $@. | optionalSanitizer.js:26:16:26:39 | documen ... .search | user-provided value |
22892353
| optionalSanitizer.js:45:18:45:56 | sanitiz ... target | optionalSanitizer.js:26:16:26:39 | documen ... .search | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | Cross-site scripting vulnerability due to $@. | optionalSanitizer.js:26:16:26:39 | documen ... .search | user-provided value |
2354+
| pages/[id].jsx:10:44:10:45 | id | pages/[id].jsx:5:18:5:29 | router.query | pages/[id].jsx:10:44:10:45 | id | Cross-site scripting vulnerability due to $@. | pages/[id].jsx:5:18:5:29 | router.query | user-provided value |
2355+
| pages/[id].jsx:13:44:13:52 | params.id | pages/[id].jsx:25:11:25:24 | context.params | pages/[id].jsx:13:44:13:52 | params.id | Cross-site scripting vulnerability due to $@. | pages/[id].jsx:25:11:25:24 | context.params | user-provided value |
2356+
| pages/[id].jsx:16:44:16:51 | params.q | pages/[id].jsx:26:10:26:22 | context.query | pages/[id].jsx:16:44:16:51 | params.q | Cross-site scripting vulnerability due to $@. | pages/[id].jsx:26:10:26:22 | context.query | user-provided value |
22902357
| react-native.js:8:18:8:24 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:8:18:8:24 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value |
22912358
| 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 |
22922359
| 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 |

javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,38 @@ nodes
516516
| optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) |
517517
| optionalSanitizer.js:45:41:45:46 | target |
518518
| optionalSanitizer.js:45:51:45:56 | target |
519+
| pages/[id].jsx:5:9:5:14 | { id } |
520+
| pages/[id].jsx:5:9:5:14 | { id } |
521+
| pages/[id].jsx:5:9:5:29 | id |
522+
| pages/[id].jsx:5:9:5:29 | id |
523+
| pages/[id].jsx:5:11:5:12 | id |
524+
| pages/[id].jsx:5:11:5:12 | id |
525+
| pages/[id].jsx:5:18:5:29 | router.query |
526+
| pages/[id].jsx:5:18:5:29 | router.query |
527+
| pages/[id].jsx:5:18:5:29 | router.query |
528+
| pages/[id].jsx:10:44:10:45 | id |
529+
| pages/[id].jsx:10:44:10:45 | id |
530+
| pages/[id].jsx:10:44:10:45 | id |
531+
| pages/[id].jsx:13:44:13:52 | params.id |
532+
| pages/[id].jsx:13:44:13:52 | params.id |
533+
| pages/[id].jsx:13:44:13:52 | params.id |
534+
| pages/[id].jsx:16:44:16:51 | params.q |
535+
| pages/[id].jsx:16:44:16:51 | params.q |
536+
| pages/[id].jsx:16:44:16:51 | params.q |
537+
| pages/[id].jsx:25:11:25:24 | context.params |
538+
| pages/[id].jsx:25:11:25:24 | context.params |
539+
| pages/[id].jsx:25:11:25:24 | context.params |
540+
| pages/[id].jsx:25:11:25:27 | context.params.id |
541+
| pages/[id].jsx:25:11:25:27 | context.params.id |
542+
| pages/[id].jsx:25:11:25:33 | context ... d \|\| "" |
543+
| pages/[id].jsx:25:11:25:33 | context ... d \|\| "" |
544+
| pages/[id].jsx:26:10:26:22 | context.query |
545+
| pages/[id].jsx:26:10:26:22 | context.query |
546+
| pages/[id].jsx:26:10:26:22 | context.query |
547+
| pages/[id].jsx:26:10:26:30 | context ... .foobar |
548+
| pages/[id].jsx:26:10:26:30 | context ... .foobar |
549+
| pages/[id].jsx:26:10:26:36 | context ... r \|\| "" |
550+
| pages/[id].jsx:26:10:26:36 | context ... r \|\| "" |
519551
| react-native.js:7:7:7:33 | tainted |
520552
| react-native.js:7:7:7:33 | tainted |
521553
| react-native.js:7:17:7:33 | req.param("code") |
@@ -1666,6 +1698,38 @@ edges
16661698
| optionalSanitizer.js:45:41:45:46 | target | optionalSanitizer.js:45:29:45:47 | sanitizeBad(target) |
16671699
| optionalSanitizer.js:45:51:45:56 | target | optionalSanitizer.js:45:18:45:56 | sanitiz ... target |
16681700
| optionalSanitizer.js:45:51:45:56 | target | optionalSanitizer.js:45:18:45:56 | sanitiz ... target |
1701+
| pages/[id].jsx:5:9:5:14 | { id } | pages/[id].jsx:5:11:5:12 | id |
1702+
| pages/[id].jsx:5:9:5:14 | { id } | pages/[id].jsx:5:11:5:12 | id |
1703+
| pages/[id].jsx:5:9:5:29 | id | pages/[id].jsx:10:44:10:45 | id |
1704+
| pages/[id].jsx:5:9:5:29 | id | pages/[id].jsx:10:44:10:45 | id |
1705+
| pages/[id].jsx:5:9:5:29 | id | pages/[id].jsx:10:44:10:45 | id |
1706+
| pages/[id].jsx:5:9:5:29 | id | pages/[id].jsx:10:44:10:45 | id |
1707+
| pages/[id].jsx:5:11:5:12 | id | pages/[id].jsx:5:9:5:29 | id |
1708+
| pages/[id].jsx:5:11:5:12 | id | pages/[id].jsx:5:9:5:29 | id |
1709+
| pages/[id].jsx:5:18:5:29 | router.query | pages/[id].jsx:5:9:5:14 | { id } |
1710+
| pages/[id].jsx:5:18:5:29 | router.query | pages/[id].jsx:5:9:5:14 | { id } |
1711+
| pages/[id].jsx:5:18:5:29 | router.query | pages/[id].jsx:5:9:5:14 | { id } |
1712+
| pages/[id].jsx:5:18:5:29 | router.query | pages/[id].jsx:5:9:5:14 | { id } |
1713+
| pages/[id].jsx:25:11:25:24 | context.params | pages/[id].jsx:25:11:25:27 | context.params.id |
1714+
| pages/[id].jsx:25:11:25:24 | context.params | pages/[id].jsx:25:11:25:27 | context.params.id |
1715+
| pages/[id].jsx:25:11:25:24 | context.params | pages/[id].jsx:25:11:25:27 | context.params.id |
1716+
| pages/[id].jsx:25:11:25:24 | context.params | pages/[id].jsx:25:11:25:27 | context.params.id |
1717+
| pages/[id].jsx:25:11:25:27 | context.params.id | pages/[id].jsx:25:11:25:33 | context ... d \|\| "" |
1718+
| pages/[id].jsx:25:11:25:27 | context.params.id | pages/[id].jsx:25:11:25:33 | context ... d \|\| "" |
1719+
| pages/[id].jsx:25:11:25:33 | context ... d \|\| "" | pages/[id].jsx:13:44:13:52 | params.id |
1720+
| pages/[id].jsx:25:11:25:33 | context ... d \|\| "" | pages/[id].jsx:13:44:13:52 | params.id |
1721+
| pages/[id].jsx:25:11:25:33 | context ... d \|\| "" | pages/[id].jsx:13:44:13:52 | params.id |
1722+
| pages/[id].jsx:25:11:25:33 | context ... d \|\| "" | pages/[id].jsx:13:44:13:52 | params.id |
1723+
| pages/[id].jsx:26:10:26:22 | context.query | pages/[id].jsx:26:10:26:30 | context ... .foobar |
1724+
| pages/[id].jsx:26:10:26:22 | context.query | pages/[id].jsx:26:10:26:30 | context ... .foobar |
1725+
| pages/[id].jsx:26:10:26:22 | context.query | pages/[id].jsx:26:10:26:30 | context ... .foobar |
1726+
| pages/[id].jsx:26:10:26:22 | context.query | pages/[id].jsx:26:10:26:30 | context ... .foobar |
1727+
| pages/[id].jsx:26:10:26:30 | context ... .foobar | pages/[id].jsx:26:10:26:36 | context ... r \|\| "" |
1728+
| pages/[id].jsx:26:10:26:30 | context ... .foobar | pages/[id].jsx:26:10:26:36 | context ... r \|\| "" |
1729+
| pages/[id].jsx:26:10:26:36 | context ... r \|\| "" | pages/[id].jsx:16:44:16:51 | params.q |
1730+
| pages/[id].jsx:26:10:26:36 | context ... r \|\| "" | pages/[id].jsx:16:44:16:51 | params.q |
1731+
| pages/[id].jsx:26:10:26:36 | context ... r \|\| "" | pages/[id].jsx:16:44:16:51 | params.q |
1732+
| pages/[id].jsx:26:10:26:36 | context ... r \|\| "" | pages/[id].jsx:16:44:16:51 | params.q |
16691733
| react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted |
16701734
| react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted |
16711735
| react-native.js:7:7:7:33 | tainted | react-native.js:8:18:8:24 | tainted |
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "my-app",
3+
"version": "0.1.0",
4+
"scripts": {
5+
"dev": "next dev",
6+
"build": "next build",
7+
"start": "next start"
8+
},
9+
"dependencies": {
10+
"next": "^10.0.0",
11+
"react": "17.0.1",
12+
"react-dom": "17.0.1"
13+
}
14+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { useRouter } from 'next/router'
2+
3+
export default function Post(params) {
4+
const router = useRouter()
5+
const { id } = router.query
6+
7+
return (
8+
<>
9+
<div
10+
dangerouslySetInnerHTML={{ __html: id }} // NOT OK
11+
/>
12+
<div
13+
dangerouslySetInnerHTML={{ __html: params.id }} // NOT OK
14+
/>
15+
<div
16+
dangerouslySetInnerHTML={{ __html: params.q }} // NOT OK
17+
/>
18+
</>
19+
)
20+
}
21+
22+
export async function getServerSideProps(context) {
23+
return {
24+
props: {
25+
id: context.params.id || "",
26+
q: context.query?.foobar || "",
27+
}
28+
}
29+
}

0 commit comments

Comments
 (0)