Skip to content

Commit 0245b9d

Browse files
authored
Merge pull request #20911 from asgerf/js/next-folders
JS: Fix project layout detection for Next.js apps
2 parents 85cb3e0 + 5b4e114 commit 0245b9d

File tree

5 files changed

+50
-3
lines changed

5 files changed

+50
-3
lines changed

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

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,31 @@ module NextJS {
1313
*/
1414
PackageJson getANextPackage() { result.getDependencies().getADependency("next", _) }
1515

16+
bindingset[base, name]
17+
pragma[inline_late]
18+
private Folder getOptionalFolder(Folder base, string name) {
19+
result = base.getFolder(name)
20+
or
21+
not exists(base.getFolder(name)) and
22+
result = base
23+
}
24+
25+
private Folder packageRoot() { result = getANextPackage().getFile().getParentContainer() }
26+
27+
private Folder srcRoot() { result = getOptionalFolder(packageRoot(), "src") }
28+
29+
private Folder appRoot() { result = srcRoot().getFolder("app") }
30+
31+
private Folder pagesRoot() { result = [srcRoot(), appRoot()].getFolder("pages") }
32+
33+
private Folder apiRoot() { result = [pagesRoot(), appRoot()].getFolder("api") }
34+
1635
/**
1736
* Gets a "pages" folder in a `Next.js` application.
1837
* JavaScript files inside these folders are mapped to routes.
1938
*/
2039
Folder getAPagesFolder() {
21-
result = getANextPackage().getFile().getParentContainer().getFolder("pages")
40+
result = pagesRoot()
2241
or
2342
result = getAPagesFolder().getAFolder()
2443
}
@@ -217,8 +236,7 @@ module NextJS {
217236
* the App Router (`app/api/`) Next.js 13+ structures.
218237
*/
219238
Folder apiFolder() {
220-
result =
221-
getANextPackage().getFile().getParentContainer().getFolder(["pages", "app"]).getFolder("api") or
239+
result = apiRoot() or
222240
result = apiFolder().getAFolder()
223241
}
224242

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Fixed a bug in the Next.js model that would cause the analysis to miss server-side taint sources in the `app/pages` folder.

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
| app/api/routeNextRequest.ts:15:20:15:23 | body | app/api/routeNextRequest.ts:4:22:4:31 | req.json() | app/api/routeNextRequest.ts:15:20:15:23 | body | Cross-site scripting vulnerability due to a $@. | app/api/routeNextRequest.ts:4:22:4:31 | req.json() | user-provided value |
3636
| app/api/routeNextRequest.ts:27:20:27:23 | body | app/api/routeNextRequest.ts:4:22:4:31 | req.json() | app/api/routeNextRequest.ts:27:20:27:23 | body | Cross-site scripting vulnerability due to a $@. | app/api/routeNextRequest.ts:4:22:4:31 | req.json() | user-provided value |
3737
| app/api/routeNextRequest.ts:31:27:31:30 | body | app/api/routeNextRequest.ts:4:22:4:31 | req.json() | app/api/routeNextRequest.ts:31:27:31:30 | body | Cross-site scripting vulnerability due to a $@. | app/api/routeNextRequest.ts:4:22:4:31 | req.json() | user-provided value |
38+
| app/pages/Next2.jsx:8:13:8:19 | req.url | app/pages/Next2.jsx:8:13:8:19 | req.url | app/pages/Next2.jsx:8:13:8:19 | req.url | Cross-site scripting vulnerability due to a $@. | app/pages/Next2.jsx:8:13:8:19 | req.url | user-provided value |
39+
| app/pages/Next2.jsx:15:13:15:19 | req.url | app/pages/Next2.jsx:15:13:15:19 | req.url | app/pages/Next2.jsx:15:13:15:19 | req.url | Cross-site scripting vulnerability due to a $@. | app/pages/Next2.jsx:15:13:15:19 | req.url | user-provided value |
3840
| etherpad.js:11:12:11:19 | response | etherpad.js:9:16:9:30 | req.query.jsonp | etherpad.js:11:12:11:19 | response | Cross-site scripting vulnerability due to a $@. | etherpad.js:9:16:9:30 | req.query.jsonp | user-provided value |
3941
| formatting.js:6:14:6:47 | util.fo ... , evil) | formatting.js:4:16:4:29 | req.query.evil | formatting.js:6:14:6:47 | util.fo ... , evil) | Cross-site scripting vulnerability due to a $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value |
4042
| formatting.js:7:14:7:53 | require ... , evil) | formatting.js:4:16:4:29 | req.query.evil | formatting.js:7:14:7:53 | require ... , evil) | Cross-site scripting vulnerability due to a $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value |
@@ -365,6 +367,8 @@ nodes
365367
| app/api/routeNextRequest.ts:15:20:15:23 | body | semmle.label | body |
366368
| app/api/routeNextRequest.ts:27:20:27:23 | body | semmle.label | body |
367369
| app/api/routeNextRequest.ts:31:27:31:30 | body | semmle.label | body |
370+
| app/pages/Next2.jsx:8:13:8:19 | req.url | semmle.label | req.url |
371+
| app/pages/Next2.jsx:15:13:15:19 | req.url | semmle.label | req.url |
368372
| etherpad.js:9:5:9:12 | response | semmle.label | response |
369373
| etherpad.js:9:16:9:30 | req.query.jsonp | semmle.label | req.query.jsonp |
370374
| etherpad.js:11:12:11:19 | response | semmle.label | response |

javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
| app/api/routeNextRequest.ts:15:20:15:23 | body | Cross-site scripting vulnerability due to $@. | app/api/routeNextRequest.ts:4:22:4:31 | req.json() | user-provided value |
3535
| app/api/routeNextRequest.ts:27:20:27:23 | body | Cross-site scripting vulnerability due to $@. | app/api/routeNextRequest.ts:4:22:4:31 | req.json() | user-provided value |
3636
| app/api/routeNextRequest.ts:31:27:31:30 | body | Cross-site scripting vulnerability due to $@. | app/api/routeNextRequest.ts:4:22:4:31 | req.json() | user-provided value |
37+
| app/pages/Next2.jsx:8:13:8:19 | req.url | Cross-site scripting vulnerability due to $@. | app/pages/Next2.jsx:8:13:8:19 | req.url | user-provided value |
38+
| app/pages/Next2.jsx:15:13:15:19 | req.url | Cross-site scripting vulnerability due to $@. | app/pages/Next2.jsx:15:13:15:19 | req.url | user-provided value |
3739
| formatting.js:6:14:6:47 | util.fo ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value |
3840
| formatting.js:7:14:7:53 | require ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value |
3941
| live-server.js:6:13:6:50 | `<html> ... /html>` | Cross-site scripting vulnerability due to $@. | live-server.js:4:21:4:27 | req.url | user-provided value |
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
export default function Post() {
2+
return <span />;
3+
}
4+
5+
Post.getInitialProps = async (ctx) => {
6+
const req = ctx.req;
7+
const res = ctx.res;
8+
res.end(req.url); // $ Alert
9+
return {}
10+
}
11+
12+
export async function getServerSideProps(ctx) {
13+
const req = ctx.req;
14+
const res = ctx.res;
15+
res.end(req.url); // $ Alert
16+
return {
17+
props: {}
18+
}
19+
}

0 commit comments

Comments
 (0)