Skip to content

Commit a79c30a

Browse files
committed
support NextJS API endpoints
1 parent 0e7e3e6 commit a79c30a

File tree

4 files changed

+39
-0
lines changed

4 files changed

+39
-0
lines changed

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,4 +193,34 @@ module NextJS {
193193

194194
override HTTP::RouteHandler getRouteHandler() { result = rh }
195195
}
196+
197+
/**
198+
* Gets a folder that contains API endpoints for a Next.js application.
199+
* These API endpoints act as Express-like route-handlers.
200+
*/
201+
Folder apiFolder() {
202+
result = getANextPackage().getFile().getParentContainer().getFolder("pages").getFolder("api")
203+
or
204+
result = apiFolder().getAFolder()
205+
}
206+
207+
/**
208+
* A Next.js route handler for an API endpoint.
209+
* The response (res) includes a set of Express.js-like methods,
210+
* and we therefore model the routehandler as an Express.js routehandler.
211+
*/
212+
class NextAPIRouteHandler extends DataFlow::FunctionNode, Express::RouteHandler,
213+
HTTP::Servers::StandardRouteHandler {
214+
NextAPIRouteHandler() {
215+
exists(Module mod | mod.getFile().getParentContainer() = apiFolder() |
216+
this = mod.getAnExportedValue("default").getAFunctionValue()
217+
)
218+
}
219+
220+
override Parameter getRouteHandlerParameter(string kind) {
221+
kind = "request" and result = getFunction().getParameter(0)
222+
or
223+
kind = "response" and result = getFunction().getParameter(1)
224+
}
225+
}
196226
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ nodes
109109
| pages/Next.jsx:15:13:15:19 | req.url |
110110
| pages/Next.jsx:15:13:15:19 | req.url |
111111
| pages/Next.jsx:15:13:15:19 | req.url |
112+
| pages/api/myapi.js:2:14:2:20 | req.url |
113+
| pages/api/myapi.js:2:14:2:20 | req.url |
114+
| pages/api/myapi.js:2:14:2:20 | req.url |
112115
| partial.js:9:25:9:25 | x |
113116
| partial.js:10:14:10:14 | x |
114117
| partial.js:10:14:10:18 | x + y |
@@ -245,6 +248,7 @@ edges
245248
| formatting.js:7:49:7:52 | evil | formatting.js:7:14:7:53 | require ... , evil) |
246249
| pages/Next.jsx:8:13:8:19 | req.url | pages/Next.jsx:8:13:8:19 | req.url |
247250
| pages/Next.jsx:15:13:15:19 | req.url | pages/Next.jsx:15:13:15:19 | req.url |
251+
| pages/api/myapi.js:2:14:2:20 | req.url | pages/api/myapi.js:2:14:2:20 | req.url |
248252
| partial.js:9:25:9:25 | x | partial.js:10:14:10:14 | x |
249253
| partial.js:10:14:10:14 | x | partial.js:10:14:10:18 | x + y |
250254
| partial.js:10:14:10:14 | x | partial.js:10:14:10:18 | x + y |
@@ -313,6 +317,7 @@ edges
313317
| 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 $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value |
314318
| pages/Next.jsx:8:13:8:19 | req.url | pages/Next.jsx:8:13:8:19 | req.url | pages/Next.jsx:8:13:8:19 | req.url | Cross-site scripting vulnerability due to $@. | pages/Next.jsx:8:13:8:19 | req.url | user-provided value |
315319
| pages/Next.jsx:15:13:15:19 | req.url | pages/Next.jsx:15:13:15:19 | req.url | pages/Next.jsx:15:13:15:19 | req.url | Cross-site scripting vulnerability due to $@. | pages/Next.jsx:15:13:15:19 | req.url | user-provided value |
320+
| pages/api/myapi.js:2:14:2:20 | req.url | pages/api/myapi.js:2:14:2:20 | req.url | pages/api/myapi.js:2:14:2:20 | req.url | Cross-site scripting vulnerability due to $@. | pages/api/myapi.js:2:14:2:20 | req.url | user-provided value |
316321
| partial.js:10:14:10:18 | x + y | partial.js:13:42:13:48 | req.url | partial.js:10:14:10:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:13:42:13:48 | req.url | user-provided value |
317322
| partial.js:19:14:19:18 | x + y | partial.js:22:51:22:57 | req.url | partial.js:19:14:19:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:22:51:22:57 | req.url | user-provided value |
318323
| partial.js:28:14:28:18 | x + y | partial.js:31:47:31:53 | req.url | partial.js:28:14:28:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:31:47:31:53 | req.url | user-provided value |

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
| 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 |
2424
| pages/Next.jsx:8:13:8:19 | req.url | Cross-site scripting vulnerability due to $@. | pages/Next.jsx:8:13:8:19 | req.url | user-provided value |
2525
| pages/Next.jsx:15:13:15:19 | req.url | Cross-site scripting vulnerability due to $@. | pages/Next.jsx:15:13:15:19 | req.url | user-provided value |
26+
| pages/api/myapi.js:2:14:2:20 | req.url | Cross-site scripting vulnerability due to $@. | pages/api/myapi.js:2:14:2:20 | req.url | user-provided value |
2627
| partial.js:10:14:10:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:13:42:13:48 | req.url | user-provided value |
2728
| partial.js:19:14:19:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:22:51:22:57 | req.url | user-provided value |
2829
| partial.js:28:14:28:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:31:47:31:53 | req.url | user-provided value |
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function handler(req, res) {
2+
res.send(req.url);
3+
}

0 commit comments

Comments
 (0)