Added searchParams.get as potential source for SSRF

This commit is contained in:
Napalys
2025-04-11 09:27:54 +02:00
parent 8674b61e5a
commit 678eccb417
3 changed files with 19 additions and 3 deletions

View File

@@ -318,7 +318,17 @@ module NextJS {
) and
kind = "body"
or
this = handler.getRequest().getAPropertyRead(["url", "nextUrl"]) and kind = "url"
(
this = handler.getRequest().getAPropertyRead(["url", "nextUrl"])
or
this =
handler
.getRequest()
.getAPropertyRead("nextUrl")
.getAPropertyRead("searchParams")
.getAMemberCall("get")
) and
kind = "url"
or
this = handler.getRequest().getAPropertyRead("headers") and kind = "headers"
}

View File

@@ -2,14 +2,14 @@ import { NextRequest, NextResponse } from 'next/server';
export async function middleware(req: NextRequest) {
const target = req.nextUrl // $ Source[js/request-forgery]
const target2 = target.searchParams.get('target'); // $ MISSING: Source[js/request-forgery]
const target2 = target.searchParams.get('target'); // $ Source[js/request-forgery]
if (target) {
const res = await fetch(target) // $ Alert[js/request-forgery] Sink[js/request-forgery]
const data = await res.text()
return new NextResponse(data)
}
if (target2) {
const res = await fetch(target2); // $ MISSING: Alert[js/request-forgery] Sink[js/request-forgery]
const res = await fetch(target2); // $ Alert[js/request-forgery] Sink[js/request-forgery]
const data = await res.text();
return new NextResponse(data);
}

View File

@@ -2,6 +2,7 @@
| Request/app/api/proxy/route2.serverSide.ts:5:21:5:30 | fetch(url) | Request/app/api/proxy/route2.serverSide.ts:4:25:4:34 | req.json() | Request/app/api/proxy/route2.serverSide.ts:5:27:5:29 | url | The $@ of this request depends on a $@. | Request/app/api/proxy/route2.serverSide.ts:5:27:5:29 | url | URL | Request/app/api/proxy/route2.serverSide.ts:4:25:4:34 | req.json() | user-provided value |
| Request/app/api/proxy/route.serverSide.ts:3:21:3:30 | fetch(url) | Request/app/api/proxy/route.serverSide.ts:2:25:2:34 | req.json() | Request/app/api/proxy/route.serverSide.ts:3:27:3:29 | url | The $@ of this request depends on a $@. | Request/app/api/proxy/route.serverSide.ts:3:27:3:29 | url | URL | Request/app/api/proxy/route.serverSide.ts:2:25:2:34 | req.json() | user-provided value |
| Request/middleware.ts:7:25:7:37 | fetch(target) | Request/middleware.ts:4:20:4:30 | req.nextUrl | Request/middleware.ts:7:31:7:36 | target | The $@ of this request depends on a $@. | Request/middleware.ts:7:31:7:36 | target | URL | Request/middleware.ts:4:20:4:30 | req.nextUrl | user-provided value |
| Request/middleware.ts:12:27:12:40 | fetch(target2) | Request/middleware.ts:5:21:5:53 | target. ... arget') | Request/middleware.ts:12:33:12:39 | target2 | The $@ of this request depends on a $@. | Request/middleware.ts:12:33:12:39 | target2 | URL | Request/middleware.ts:5:21:5:53 | target. ... arget') | user-provided value |
| apollo.serverSide.ts:8:39:8:64 | get(fil ... => {}) | apollo.serverSide.ts:7:36:7:44 | { files } | apollo.serverSide.ts:8:43:8:50 | file.url | The $@ of this request depends on a $@. | apollo.serverSide.ts:8:43:8:50 | file.url | URL | apollo.serverSide.ts:7:36:7:44 | { files } | user-provided value |
| apollo.serverSide.ts:18:37:18:62 | get(fil ... => {}) | apollo.serverSide.ts:17:34:17:42 | { files } | apollo.serverSide.ts:18:41:18:48 | file.url | The $@ of this request depends on a $@. | apollo.serverSide.ts:18:41:18:48 | file.url | URL | apollo.serverSide.ts:17:34:17:42 | { files } | user-provided value |
| axiosInterceptors.serverSide.js:11:26:11:40 | userProvidedUrl | axiosInterceptors.serverSide.js:19:21:19:28 | req.body | axiosInterceptors.serverSide.js:11:26:11:40 | userProvidedUrl | The $@ of this request depends on a $@. | axiosInterceptors.serverSide.js:11:26:11:40 | userProvidedUrl | endpoint | axiosInterceptors.serverSide.js:19:21:19:28 | req.body | user-provided value |
@@ -40,6 +41,8 @@ edges
| Request/app/api/proxy/route.serverSide.ts:2:25:2:34 | req.json() | Request/app/api/proxy/route.serverSide.ts:2:19:2:34 | await req.json() | provenance | |
| Request/middleware.ts:4:11:4:30 | target | Request/middleware.ts:7:31:7:36 | target | provenance | |
| Request/middleware.ts:4:20:4:30 | req.nextUrl | Request/middleware.ts:4:11:4:30 | target | provenance | |
| Request/middleware.ts:5:11:5:53 | target2 | Request/middleware.ts:12:33:12:39 | target2 | provenance | |
| Request/middleware.ts:5:21:5:53 | target. ... arget') | Request/middleware.ts:5:11:5:53 | target2 | provenance | |
| apollo.serverSide.ts:7:36:7:44 | files | apollo.serverSide.ts:8:13:8:17 | files | provenance | |
| apollo.serverSide.ts:7:36:7:44 | { files } | apollo.serverSide.ts:7:36:7:44 | files | provenance | |
| apollo.serverSide.ts:8:13:8:17 | files | apollo.serverSide.ts:8:28:8:31 | file | provenance | |
@@ -116,7 +119,10 @@ nodes
| Request/app/api/proxy/route.serverSide.ts:3:27:3:29 | url | semmle.label | url |
| Request/middleware.ts:4:11:4:30 | target | semmle.label | target |
| Request/middleware.ts:4:20:4:30 | req.nextUrl | semmle.label | req.nextUrl |
| Request/middleware.ts:5:11:5:53 | target2 | semmle.label | target2 |
| Request/middleware.ts:5:21:5:53 | target. ... arget') | semmle.label | target. ... arget') |
| Request/middleware.ts:7:31:7:36 | target | semmle.label | target |
| Request/middleware.ts:12:33:12:39 | target2 | semmle.label | target2 |
| apollo.serverSide.ts:7:36:7:44 | files | semmle.label | files |
| apollo.serverSide.ts:7:36:7:44 | { files } | semmle.label | { files } |
| apollo.serverSide.ts:8:13:8:17 | files | semmle.label | files |