Merge pull request #19099 from Napalys/js/axios_missing_methods

JS: Added support for missing `axios` methods
This commit is contained in:
Napalys Klicius
2025-03-27 12:03:11 +01:00
committed by GitHub
9 changed files with 123 additions and 1 deletions

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
Enhanced `axios` support with new methods (`postForm`, `putForm`, `patchForm`, `getUri`, `create`) and added support for `interceptors.request` and `interceptors.response`.

View File

@@ -0,0 +1,12 @@
extensions:
- addsTo:
pack: codeql/javascript-all
extensible: sinkModel
data:
- ["axios", "Member[interceptors].Member[request].Member[use].Argument[0].Parameter[0].Member[url]", "request-forgery"]
- addsTo:
pack: codeql/javascript-all
extensible: sourceModel
data:
- ["axios", "Member[interceptors].Member[response].Member[use].Argument[0].Parameter[0]", "response"]

View File

@@ -222,7 +222,10 @@ module ClientRequest {
method = "request"
or
this = axios().getMember(method).getACall() and
method = [httpMethodName(), "request"]
method = [httpMethodName(), "request", "postForm", "putForm", "patchForm", "getUri"]
or
this = axios().getMember("create").getReturn().getACall() and
method = "request"
}
private int getOptionsArgIndex() {
@@ -254,6 +257,8 @@ module ClientRequest {
method = ["post", "put"] and
result = [this.getArgument(1), this.getOptionArgument(2, "data")]
or
method = ["postForm", "putForm", "patchForm"] and result = this.getArgument(1)
or
result = this.getOptionArgument([0 .. 2], ["headers", "params"])
}

View File

@@ -103,6 +103,13 @@ test_ClientRequest
| tst.js:334:5:334:25 | got.pag ... rl, {}) |
| tst.js:337:5:337:20 | jsonClient.get() |
| tst.js:340:5:340:21 | jsonClient2.get() |
| tst.js:344:5:344:37 | axios.p ... config) |
| tst.js:345:5:345:28 | axios.p ... , data) |
| tst.js:346:5:346:36 | axios.p ... config) |
| tst.js:347:5:347:30 | axios.p ... , data) |
| tst.js:348:5:348:38 | axios.p ... config) |
| tst.js:349:5:349:30 | axios.g ... url }) |
| tst.js:352:5:352:66 | axiosIn ... text"}) |
test_getADataNode
| axiosTest.js:12:5:17:6 | axios({ ... \\n }) | axiosTest.js:15:18:15:55 | { 'Cont ... json' } |
| axiosTest.js:12:5:17:6 | axios({ ... \\n }) | axiosTest.js:16:15:16:35 | {x: 'te ... 'test'} |
@@ -146,6 +153,11 @@ test_getADataNode
| tst.js:257:1:262:2 | form.su ... rs()\\n}) | tst.js:255:25:255:35 | 'new_value' |
| tst.js:286:20:286:55 | new Web ... :8080') | tst.js:288:21:288:35 | 'Hello Server!' |
| tst.js:321:5:321:32 | superag ... st(url) | tst.js:321:39:321:42 | data |
| tst.js:344:5:344:37 | axios.p ... config) | tst.js:344:25:344:28 | data |
| tst.js:345:5:345:28 | axios.p ... , data) | tst.js:345:24:345:27 | data |
| tst.js:346:5:346:36 | axios.p ... config) | tst.js:346:24:346:27 | data |
| tst.js:347:5:347:30 | axios.p ... , data) | tst.js:347:26:347:29 | data |
| tst.js:348:5:348:38 | axios.p ... config) | tst.js:348:26:348:29 | data |
test_getHost
| tst.js:87:5:87:39 | http.ge ... host}) | tst.js:87:34:87:37 | host |
| tst.js:89:5:89:23 | axios({host: host}) | tst.js:89:18:89:21 | host |
@@ -268,6 +280,14 @@ test_getUrl
| tst.js:337:5:337:20 | jsonClient.get() | tst.js:336:41:336:43 | url |
| tst.js:340:5:340:21 | jsonClient2.get() | tst.js:339:42:339:44 | url |
| tst.js:340:5:340:21 | jsonClient2.get() | tst.js:339:61:339:63 | url |
| tst.js:344:5:344:37 | axios.p ... config) | tst.js:344:20:344:22 | url |
| tst.js:345:5:345:28 | axios.p ... , data) | tst.js:345:19:345:21 | url |
| tst.js:346:5:346:36 | axios.p ... config) | tst.js:346:19:346:21 | url |
| tst.js:347:5:347:30 | axios.p ... , data) | tst.js:347:21:347:23 | url |
| tst.js:348:5:348:38 | axios.p ... config) | tst.js:348:21:348:23 | url |
| tst.js:349:5:349:30 | axios.g ... url }) | tst.js:349:18:349:29 | { url: url } |
| tst.js:352:5:352:66 | axiosIn ... text"}) | tst.js:352:19:352:65 | {method ... "text"} |
| tst.js:352:5:352:66 | axiosIn ... text"}) | tst.js:352:40:352:42 | url |
test_getAResponseDataNode
| axiosTest.js:4:5:7:6 | axios({ ... \\n }) | axiosTest.js:4:5:7:6 | axios({ ... \\n }) | json | true |
| axiosTest.js:12:5:17:6 | axios({ ... \\n }) | axiosTest.js:12:5:17:6 | axios({ ... \\n }) | json | true |
@@ -354,3 +374,10 @@ test_getAResponseDataNode
| tst.js:334:5:334:25 | got.pag ... rl, {}) | tst.js:334:5:334:25 | got.pag ... rl, {}) | text | true |
| tst.js:337:5:337:20 | jsonClient.get() | tst.js:337:5:337:20 | jsonClient.get() | text | true |
| tst.js:340:5:340:21 | jsonClient2.get() | tst.js:340:5:340:21 | jsonClient2.get() | text | true |
| tst.js:344:5:344:37 | axios.p ... config) | tst.js:344:5:344:37 | axios.p ... config) | json | true |
| tst.js:345:5:345:28 | axios.p ... , data) | tst.js:345:5:345:28 | axios.p ... , data) | json | true |
| tst.js:346:5:346:36 | axios.p ... config) | tst.js:346:5:346:36 | axios.p ... config) | json | true |
| tst.js:347:5:347:30 | axios.p ... , data) | tst.js:347:5:347:30 | axios.p ... , data) | json | true |
| tst.js:348:5:348:38 | axios.p ... config) | tst.js:348:5:348:38 | axios.p ... config) | json | true |
| tst.js:349:5:349:30 | axios.g ... url }) | tst.js:349:5:349:30 | axios.g ... url }) | json | true |
| tst.js:352:5:352:66 | axiosIn ... text"}) | tst.js:352:5:352:66 | axiosIn ... text"}) | text | true |

View File

@@ -339,3 +339,15 @@ function gotTests(url){
const jsonClient2 = got.extend({url: url}).extend({url: url});
jsonClient2.get();
}
function moreAxiosTests(url, data, config){
axios.postForm(url, data, config);
axios.putForm(url, data);
axios.putForm(url, data, config);
axios.patchForm(url, data);
axios.patchForm(url, data, config);
axios.getUri({ url: url });
const axiosInstance = axios.create({});
axiosInstance({method: "get", url: url, responseType: "text"});
}

View File

@@ -1,4 +1,5 @@
#select
| interceptors.js:9:56:9:72 | userGeneratedHtml | interceptors.js:7:6:7:13 | response | interceptors.js:9:56:9:72 | userGeneratedHtml | Cross-site scripting vulnerability due to $@. | interceptors.js:7:6:7:13 | response | user-provided value |
| test.jsx:27:29:27:32 | data | test.jsx:5:28:5:63 | fetch(" ... ntent") | test.jsx:27:29:27:32 | data | Cross-site scripting vulnerability due to $@. | test.jsx:5:28:5:63 | fetch(" ... ntent") | user-provided value |
| test.ts:21:57:21:76 | response.description | test.ts:8:9:8:79 | this.#h ... query') | test.ts:21:57:21:76 | response.description | Cross-site scripting vulnerability due to $@. | test.ts:8:9:8:79 | this.#h ... query') | user-provided value |
| test.ts:24:36:24:90 | `<h2>${ ... o}</p>` | test.ts:8:9:8:79 | this.#h ... query') | test.ts:24:36:24:90 | `<h2>${ ... o}</p>` | Cross-site scripting vulnerability due to $@. | test.ts:8:9:8:79 | this.#h ... query') | user-provided value |
@@ -18,6 +19,9 @@
| testUseQueries2.vue:40:10:40:23 | v-html=data3 | testUseQueries2.vue:12:28:12:41 | fetch("${id}") | testUseQueries2.vue:40:10:40:23 | v-html=data3 | Cross-site scripting vulnerability due to $@. | testUseQueries2.vue:12:28:12:41 | fetch("${id}") | user-provided value |
| testUseQueries.vue:25:10:25:23 | v-html=data2 | testUseQueries.vue:11:36:11:49 | fetch("${id}") | testUseQueries.vue:25:10:25:23 | v-html=data2 | Cross-site scripting vulnerability due to $@. | testUseQueries.vue:11:36:11:49 | fetch("${id}") | user-provided value |
edges
| interceptors.js:7:6:7:13 | response | interceptors.js:8:35:8:42 | response | provenance | |
| interceptors.js:8:15:8:47 | userGeneratedHtml | interceptors.js:9:56:9:72 | userGeneratedHtml | provenance | |
| interceptors.js:8:35:8:42 | response | interceptors.js:8:15:8:47 | userGeneratedHtml | provenance | |
| test.jsx:5:11:5:63 | response | test.jsx:6:24:6:31 | response | provenance | |
| test.jsx:5:22:5:63 | await f ... ntent") | test.jsx:5:11:5:63 | response | provenance | |
| test.jsx:5:28:5:63 | fetch(" ... ntent") | test.jsx:5:22:5:63 | await f ... ntent") | provenance | |
@@ -96,6 +100,10 @@ edges
| testUseQueries.vue:12:20:12:34 | response.json() | testUseQueries.vue:18:22:18:36 | results[0].data | provenance | |
| testUseQueries.vue:18:22:18:36 | results[0].data | testUseQueries.vue:25:10:25:23 | v-html=data2 | provenance | |
nodes
| interceptors.js:7:6:7:13 | response | semmle.label | response |
| interceptors.js:8:15:8:47 | userGeneratedHtml | semmle.label | userGeneratedHtml |
| interceptors.js:8:35:8:42 | response | semmle.label | response |
| interceptors.js:9:56:9:72 | userGeneratedHtml | semmle.label | userGeneratedHtml |
| test.jsx:5:11:5:63 | response | semmle.label | response |
| test.jsx:5:22:5:63 | await f ... ntent") | semmle.label | await f ... ntent") |
| test.jsx:5:28:5:63 | fetch(" ... ntent") | semmle.label | fetch(" ... ntent") |

View File

@@ -0,0 +1,20 @@
const express = require("express");
const axios = require("axios");
const app = express();
axios.interceptors.response.use(
(response) => { // $ Source
const userGeneratedHtml = response.data;
document.getElementById("content").innerHTML = userGeneratedHtml; // $ Alert
return response;
},
(error) => {
return Promise.reject(error);
}
);
app.post("/fetch", (req, res) => {
const { url } = req.body;
axios.get(url);
});

View File

@@ -1,5 +1,6 @@
#select
| 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 |
| 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 |
| serverSide.js:18:5:18:20 | request(tainted) | serverSide.js:14:29:14:35 | req.url | serverSide.js:18:13:18:19 | tainted | The $@ of this request depends on a $@. | serverSide.js:18:13:18:19 | tainted | URL | serverSide.js:14:29:14:35 | req.url | user-provided value |
| serverSide.js:20:5:20:24 | request.get(tainted) | serverSide.js:14:29:14:35 | req.url | serverSide.js:20:17:20:23 | tainted | The $@ of this request depends on a $@. | serverSide.js:20:17:20:23 | tainted | URL | serverSide.js:14:29:14:35 | req.url | user-provided value |
| serverSide.js:24:5:24:20 | request(options) | serverSide.js:14:29:14:35 | req.url | serverSide.js:23:19:23:25 | tainted | The $@ of this request depends on a $@. | serverSide.js:23:19:23:25 | tainted | URL | serverSide.js:14:29:14:35 | req.url | user-provided value |
@@ -30,6 +31,11 @@ edges
| apollo.serverSide.ts:8:13:8:17 | files | apollo.serverSide.ts:8:28:8:31 | file | provenance | |
| apollo.serverSide.ts:8:28:8:31 | file | apollo.serverSide.ts:8:43:8:46 | file | provenance | |
| apollo.serverSide.ts:8:43:8:46 | file | apollo.serverSide.ts:8:43:8:50 | file.url | provenance | |
| axiosInterceptors.serverSide.js:19:11:19:17 | { url } | axiosInterceptors.serverSide.js:19:11:19:28 | url | provenance | |
| axiosInterceptors.serverSide.js:19:11:19:28 | url | axiosInterceptors.serverSide.js:20:23:20:25 | url | provenance | |
| axiosInterceptors.serverSide.js:19:21:19:28 | req.body | axiosInterceptors.serverSide.js:19:11:19:17 | { url } | provenance | |
| axiosInterceptors.serverSide.js:20:5:20:25 | userProvidedUrl | axiosInterceptors.serverSide.js:11:26:11:40 | userProvidedUrl | provenance | |
| axiosInterceptors.serverSide.js:20:23:20:25 | url | axiosInterceptors.serverSide.js:20:5:20:25 | userProvidedUrl | provenance | |
| serverSide.js:14:9:14:52 | tainted | serverSide.js:18:13:18:19 | tainted | provenance | |
| serverSide.js:14:9:14:52 | tainted | serverSide.js:20:17:20:23 | tainted | provenance | |
| serverSide.js:14:9:14:52 | tainted | serverSide.js:23:19:23:25 | tainted | provenance | |
@@ -85,6 +91,12 @@ nodes
| apollo.serverSide.ts:8:28:8:31 | file | semmle.label | file |
| apollo.serverSide.ts:8:43:8:46 | file | semmle.label | file |
| apollo.serverSide.ts:8:43:8:50 | file.url | semmle.label | file.url |
| axiosInterceptors.serverSide.js:11:26:11:40 | userProvidedUrl | semmle.label | userProvidedUrl |
| axiosInterceptors.serverSide.js:19:11:19:17 | { url } | semmle.label | { url } |
| axiosInterceptors.serverSide.js:19:11:19:28 | url | semmle.label | url |
| axiosInterceptors.serverSide.js:19:21:19:28 | req.body | semmle.label | req.body |
| axiosInterceptors.serverSide.js:20:5:20:25 | userProvidedUrl | semmle.label | userProvidedUrl |
| axiosInterceptors.serverSide.js:20:23:20:25 | url | semmle.label | url |
| serverSide.js:14:9:14:52 | tainted | semmle.label | tainted |
| serverSide.js:14:19:14:42 | url.par ... , true) | semmle.label | url.par ... , true) |
| serverSide.js:14:29:14:35 | req.url | semmle.label | req.url |

View File

@@ -0,0 +1,22 @@
const express = require("express");
const axios = require("axios");
const app = express();
let userProvidedUrl = "";
axios.interceptors.request.use(
function (config) {
if (userProvidedUrl) {
config.url = userProvidedUrl; // $ Alert[js/request-forgery]
}
return config;
},
error => error
);
app.post("/fetch", (req, res) => {
const { url } = req.body; // $ Source[js/request-forgery]
userProvidedUrl = url;
axios.get("placeholder");
});