JS: enchance middleware taint tracking via local source

This commit is contained in:
Napalys Klicius
2025-06-16 16:31:17 +02:00
parent da21a064ac
commit 060b98d36c
3 changed files with 11 additions and 3 deletions

View File

@@ -925,7 +925,7 @@ module Routing {
private DataFlow::Node getAnAccessPathRhs(Node base, int n, string path) {
// Assigned in the body of a route handler function, which is a middleware
exists(RouteHandler handler | base = handler |
result = AccessPath::getAnAssignmentTo(handler.getParameter(n).ref(), path) and
result = AccessPath::getAnAssignmentTo(handler.getParameter(n).ref(), path).getALocalSource() and
(
exists(handler.getAContinuationInvocation())
or

View File

@@ -6,6 +6,7 @@
| 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 |
| serverSide2.js:17:28:17:47 | axios.get(targetUrl) | serverSide2.js:10:25:10:31 | req.url | serverSide2.js:17:38:17:46 | targetUrl | The $@ of this request depends on a $@. | serverSide2.js:17:38:17:46 | targetUrl | URL | serverSide2.js:10:25:10:31 | req.url | user-provided value |
| serverSide2.js:20:29:20:49 | axios.g ... etUrl1) | serverSide2.js:9:43:9:56 | req._parsedUrl | serverSide2.js:20:39:20:48 | targetUrl1 | The $@ of this request depends on a $@. | serverSide2.js:20:39:20:48 | targetUrl1 | URL | serverSide2.js:9:43:9:56 | req._parsedUrl | user-provided value |
| serverSide2.js:23:29:23:49 | axios.g ... etUrl2) | serverSide2.js:22:24:22:30 | req.url | serverSide2.js:23:39:23:48 | targetUrl2 | The $@ of this request depends on a $@. | serverSide2.js:23:39:23:48 | targetUrl2 | URL | serverSide2.js:22:24:22:30 | req.url | user-provided value |
| serverSide2.js:26:29:26:49 | axios.g ... etUrl3) | serverSide2.js:11:24:11:30 | req.url | serverSide2.js:26:39:26:48 | targetUrl3 | The $@ of this request depends on a $@. | serverSide2.js:26:39:26:48 | targetUrl3 | URL | serverSide2.js:11:24:11:30 | req.url | user-provided value |
@@ -66,7 +67,10 @@ edges
| axiosInterceptors.serverSide.js:20:23:20:25 | url | axiosInterceptors.serverSide.js:20:5:20:25 | userProvidedUrl | provenance | |
| serverSide2.js:9:34:9:63 | qs.pars ... .query) | serverSide2.js:19:24:19:51 | req.par ... rsedUrl | provenance | |
| serverSide2.js:9:43:9:56 | req._parsedUrl | serverSide2.js:9:34:9:63 | qs.pars ... .query) | provenance | |
| serverSide2.js:10:25:10:31 | req.url | serverSide2.js:16:23:16:41 | req.parsedQuery.url | provenance | |
| serverSide2.js:11:24:11:30 | req.url | serverSide2.js:25:24:25:41 | req.SomeObject.url | provenance | |
| serverSide2.js:16:11:16:41 | targetUrl | serverSide2.js:17:38:17:46 | targetUrl | provenance | |
| serverSide2.js:16:23:16:41 | req.parsedQuery.url | serverSide2.js:16:11:16:41 | targetUrl | provenance | |
| serverSide2.js:19:11:19:55 | targetUrl1 | serverSide2.js:20:39:20:48 | targetUrl1 | provenance | |
| serverSide2.js:19:24:19:51 | req.par ... rsedUrl | serverSide2.js:19:11:19:55 | targetUrl1 | provenance | |
| serverSide2.js:22:11:22:36 | targetUrl2 | serverSide2.js:23:39:23:48 | targetUrl2 | provenance | |
@@ -167,7 +171,11 @@ nodes
| axiosInterceptors.serverSide.js:20:23:20:25 | url | semmle.label | url |
| serverSide2.js:9:34:9:63 | qs.pars ... .query) | semmle.label | qs.pars ... .query) |
| serverSide2.js:9:43:9:56 | req._parsedUrl | semmle.label | req._parsedUrl |
| serverSide2.js:10:25:10:31 | req.url | semmle.label | req.url |
| serverSide2.js:11:24:11:30 | req.url | semmle.label | req.url |
| serverSide2.js:16:11:16:41 | targetUrl | semmle.label | targetUrl |
| serverSide2.js:16:23:16:41 | req.parsedQuery.url | semmle.label | req.parsedQuery.url |
| serverSide2.js:17:38:17:46 | targetUrl | semmle.label | targetUrl |
| serverSide2.js:19:11:19:55 | targetUrl1 | semmle.label | targetUrl1 |
| serverSide2.js:19:24:19:51 | req.par ... rsedUrl | semmle.label | req.par ... rsedUrl |
| serverSide2.js:20:39:20:48 | targetUrl1 | semmle.label | targetUrl1 |

View File

@@ -7,14 +7,14 @@ const PORT = 3000;
app.use((req, res, next) => {
req.parsedQueryFromParsedUrl = qs.parse(req._parsedUrl.query); // $Source[js/request-forgery]
req.parsedQuery.url = req.url || {}; // $MISSING:Source[js/request-forgery]
req.parsedQuery.url = req.url || {}; // $Source[js/request-forgery]
req.SomeObject.url = req.url; // $Source[js/request-forgery]
next();
});
app.get('/proxy', async (req, res) => {
const targetUrl = req.parsedQuery.url;
const response = await axios.get(targetUrl); // $MISSING:Alert[js/request-forgery]
const response = await axios.get(targetUrl); // $Alert[js/request-forgery]
const targetUrl1 = req.parsedQueryFromParsedUrl.url;
const response1 = await axios.get(targetUrl1); // $Alert[js/request-forgery]