diff --git a/README.md b/README.md index 42394c2..0deb296 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,10 @@ Use "on", "off" or "cli". "cli" will show additional information at start up. Ignore missing SSL certificates for https requests. +##### `--prevent-self-calls` (**Optional**) + +Prevent self calls. Will block any request to localhost. + ### Example Below command will run a RapidAPI Testing Worker that fetches 200 new tests every 5 seconds from location queue `3866fd2aaeb474a76fdf236062660fb31df234b8`, defined for context `1234567`, with location key as `custom_worker`. @@ -91,6 +95,7 @@ Alternately, you can start the worker with preset env vars and omit the command - `BATCH_SIZE` - `WORKER_LOGGING` - `IGNORE_MISSING_SSL_CERT` +- `PREVENT_SELF_CALL` Once loaded, you can start the work without the command options: diff --git a/src/main.js b/src/main.js index f581ca7..02930b9 100755 --- a/src/main.js +++ b/src/main.js @@ -73,6 +73,11 @@ async function execute(event, _context) { "--ignore-ssl [true, false]", "Ignore a missing or self-signed SSL certificate from an API endpoint", process.env.IGNORE_MISSING_SSL_CERT || ignoreSSL + ) + .option( + "--prevent-self-calls [true, false]", + "Prevent self calls. Will block any request to localhost. (default is false)", + process.env.PREVENT_SELF_CALL || "false" ); program.parse(); @@ -101,6 +106,7 @@ async function execute(event, _context) { batchSize: cmd.batch, logging, ignoreSSL: cmd.ignoreSsl, + preventSelfCalls: cmd.preventSelfCalls, }; const START_TIMESTAMP = Date.now(); diff --git a/src/models/actions/Http.js b/src/models/actions/Http.js index 3171bd7..d1fa75c 100644 --- a/src/models/actions/Http.js +++ b/src/models/actions/Http.js @@ -81,6 +81,25 @@ class Http extends BaseAction { const safeRequestObj = this.makeRequestObject(this.safeParameters, stepTimeoutSeconds); try { + // prevent calls to local addresses + if (global.settings?.preventSelfCalls === "true") { + const localhostRegex = /^(http:\/\/)?(localhost|127\.0\.0\.1|::1)(:\d+)?(\/.*)?$/i; + if (requestObj.url && localhostRegex.test(requestObj.url)) { + return { + response: {}, + actionReports: [ + { + action: `Http.${this.method.toLowerCase()}`, + success: false, + shortSummary: "Request Blocked: Calls to local addresses are not allowed.", + longSummary: null, + time: 0, + }, + ], + }; + } + } + response = await transport.request(requestObj); } catch (e) { if (!e.response) { diff --git a/src/models/actions/Http.spec.js b/src/models/actions/Http.spec.js index 6026f90..269d4f4 100644 --- a/src/models/actions/Http.spec.js +++ b/src/models/actions/Http.spec.js @@ -84,6 +84,26 @@ describe("Http", () => { expect(typeof $result.contextWrites[0].value.data.origin).toBe("string"); }); + it("should prevent self calls", async () => { + const { HttpGet } = require("./Http"); + + global.settings = { + preventSelfCalls: "true", + }; + + let $action = new HttpGet({ + url: "http://localhost:3000", + }); + + let $result = await $action.eval(new Context()); + + expect($result.actionReports.length).toBe(1); + expect($result.actionReports[0].action).toBe("Http.get"); + expect($result.actionReports[0].success).toBe(false); + expect($result.actionReports[0].shortSummary).toBe("Request Blocked: Calls to local addresses are not allowed."); + expect(typeof $result.actionReports[0].time).toBe("number"); + }); + it("should return as success even if response code is not 2xx", async () => { const { HttpGet } = require("./Http");