diff --git a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/CommandInjection.expected b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/CommandInjection.expected index dc9c65822ba..22bcd24a578 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/CommandInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/CommandInjection.expected @@ -82,6 +82,9 @@ | other.js:28:27:28:29 | cmd | other.js:5:25:5:31 | req.url | other.js:28:27:28:29 | cmd | This command line depends on a $@. | other.js:5:25:5:31 | req.url | user-provided value | | other.js:30:33:30:35 | cmd | other.js:5:25:5:31 | req.url | other.js:30:33:30:35 | cmd | This command line depends on a $@. | other.js:5:25:5:31 | req.url | user-provided value | | other.js:34:44:34:46 | cmd | other.js:5:25:5:31 | req.url | other.js:34:44:34:46 | cmd | This command line depends on a $@. | other.js:5:25:5:31 | req.url | user-provided value | +| promisification.js:24:22:24:25 | code | promisification.js:21:18:21:25 | req.body | promisification.js:24:22:24:25 | code | This command line depends on a $@. | promisification.js:21:18:21:25 | req.body | user-provided value | +| promisification.js:52:21:52:24 | code | promisification.js:49:18:49:25 | req.body | promisification.js:52:21:52:24 | code | This command line depends on a $@. | promisification.js:49:18:49:25 | req.body | user-provided value | +| promisification.js:55:15:55:18 | code | promisification.js:49:18:49:25 | req.body | promisification.js:55:15:55:18 | code | This command line depends on a $@. | promisification.js:49:18:49:25 | req.body | user-provided value | | third-party-command-injection.js:6:21:6:27 | command | third-party-command-injection.js:5:20:5:26 | command | third-party-command-injection.js:6:21:6:27 | command | This command line depends on a $@. | third-party-command-injection.js:5:20:5:26 | command | user-provided value | edges | actions.js:8:9:8:13 | title | actions.js:9:16:9:20 | title | provenance | | @@ -259,6 +262,11 @@ edges | other.js:5:9:5:11 | cmd | other.js:34:44:34:46 | cmd | provenance | | | other.js:5:15:5:38 | url.par ... , true) | other.js:5:9:5:11 | cmd | provenance | | | other.js:5:25:5:31 | req.url | other.js:5:15:5:38 | url.par ... , true) | provenance | | +| promisification.js:21:11:21:14 | code | promisification.js:24:22:24:25 | code | provenance | | +| promisification.js:21:18:21:25 | req.body | promisification.js:21:11:21:14 | code | provenance | | +| promisification.js:49:11:49:14 | code | promisification.js:52:21:52:24 | code | provenance | | +| promisification.js:49:11:49:14 | code | promisification.js:55:15:55:18 | code | provenance | | +| promisification.js:49:18:49:25 | req.body | promisification.js:49:11:49:14 | code | provenance | | | third-party-command-injection.js:5:20:5:26 | command | third-party-command-injection.js:6:21:6:27 | command | provenance | | nodes | actions.js:8:9:8:13 | title | semmle.label | title | @@ -446,6 +454,13 @@ nodes | other.js:28:27:28:29 | cmd | semmle.label | cmd | | other.js:30:33:30:35 | cmd | semmle.label | cmd | | other.js:34:44:34:46 | cmd | semmle.label | cmd | +| promisification.js:21:11:21:14 | code | semmle.label | code | +| promisification.js:21:18:21:25 | req.body | semmle.label | req.body | +| promisification.js:24:22:24:25 | code | semmle.label | code | +| promisification.js:49:11:49:14 | code | semmle.label | code | +| promisification.js:49:18:49:25 | req.body | semmle.label | req.body | +| promisification.js:52:21:52:24 | code | semmle.label | code | +| promisification.js:55:15:55:18 | code | semmle.label | code | | third-party-command-injection.js:5:20:5:26 | command | semmle.label | command | | third-party-command-injection.js:6:21:6:27 | command | semmle.label | command | subpaths diff --git a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/promisification.js b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/promisification.js new file mode 100644 index 00000000000..09e4285b4b7 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/promisification.js @@ -0,0 +1,153 @@ +const express = require('express'); +const bodyParser = require('body-parser'); +const cp = require('child_process'); + +const app = express(); +app.use(bodyParser.json()); + +function legacyEval(code) { + cp.exec(code.code); // $ MISSING: Alert +} + +app.post('/eval', async (req, res) => { + const { promisify } = require('util'); + const evalAsync = promisify(legacyEval); + const code = req.body; // $ MISSING: Source + evalAsync(code); +}); + +app.post('/eval', async (req, res) => { + const directPromisify = require('util.promisify'); + const code = req.body; // $ Source + + const promisifiedExec3 = directPromisify(cp.exec); + promisifiedExec3(code); // $ Alert +}); + +app.post('/eval', async (req, res) => { + const promisify2 = require('util.promisify-all'); + const promisifiedCp = promisify2(cp); + const code = req.body; // $ MISSING: Source + promisifiedCp.exec(code); // $ MISSING: Alert +}); + + +app.post('/eval', async (req, res) => { + var garPromisify = require("@gar/promisify"); + const code = req.body; // $ MISSING: Source + + const promisifiedExec = garPromisify(cp.exec); + promisifiedExec(code); // $ MISSING: Alert + + const promisifiedCp = garPromisify(cp); + promisifiedCp.exec(code); // $ MISSING: Alert +}); + +app.post('/eval', async (req, res) => { + require('util.promisify/shim')(); + const util = require('util'); + const code = req.body; // $ Source + + const promisifiedExec = util.promisify(cp.exec); + promisifiedExec(code); // $ Alert + + const execAsync = util.promisify(cp.exec.bind(cp)); + execAsync(code); // $ Alert +}); + + +app.post('/eval', async (req, res) => { + const es6Promisify = require("es6-promisify"); + let cmd = req.body; // $ MISSING: Source + + // Test basic promisification + const promisifiedExec = es6Promisify(cp.exec); + promisifiedExec(cmd); // $ MISSING: Alert + + // Test with method binding + const execBoundAsync = es6Promisify(cp.exec.bind(cp)); + execBoundAsync(cmd); // $ MISSING: Alert + + const promisifiedExecMulti = es6Promisify(cp.exec, { + multiArgs: true + }); + promisifiedExecMulti(cmd); // $ MISSING: Alert + + const promisifiedCp = es6Promisify.promisifyAll(cp); + promisifiedCp.exec(cmd); // $ MISSING: Alert + promisifiedCp.execFile(cmd); // $ MISSING: Alert + promisifiedCp.spawn(cmd); // $ MISSING: Alert + + const lambda = es6Promisify((code, callback) => { + try { + const result = cp.exec(code); // $ MISSING: Alert + callback(null, result); + } catch (err) { + callback(err); + } + }); + lambda(cmd); +}); + + +app.post('/eval', async (req, res) => { + var thenifyAll = require('thenify-all'); + var cpThenifyAll = thenifyAll(require('child_process'), {}, [ + 'exec', + 'execSync', + ]); + const code = req.body; // $ MISSING: Source + cpThenifyAll.exec(code); // $ MISSING: Alert + cpThenifyAll.execSync(code); // $ MISSING: Alert + cpThenifyAll.execFile(code); // $ MISSING: Alert - not promisified, as it is not listed in `thenifyAll` + + + var cpThenifyAll1 = thenifyAll.withCallback(require('child_process'), {}, ['exec']); + cpThenifyAll1.exec(code, function (err, string) {}); // $ MISSING: Alert + + var cpThenifyAll2 = thenifyAll(require('child_process')); + cpThenifyAll2.exec(code); // $ MISSING: Alert +}); + +app.post('/eval', async (req, res) => { + const maybe = require('call-me-maybe'); + const code = req.body; // $ MISSING: Source + + function createExecPromise(cmd) { + return new Promise((resolve) => { + resolve(cmd); + }); + } + + const cmdPromise = createExecPromise(code); + maybe(null, cmdPromise).then(cmd => { + cp.exec(cmd); // $ MISSING: Alert + }); +}); + +app.post('/eval', async (req, res) => { + const utilPromisify = require('util-promisify'); + const code = req.body; // $ MISSING: Source + + const promisifiedExec = utilPromisify(cp.exec); + promisifiedExec(code); // $ MISSING: Alert + + const execAsync = utilPromisify(cp.exec.bind(cp)); + execAsync(code); // $ MISSING: Alert +}); + +app.post('/eval', async (req, res) => { + const {promisify, promisifyAll} = require('@google-cloud/promisify'); + const code = req.body; // $ MISSING: Source + + const promisifiedExec = promisify(cp.exec); + promisifiedExec(code); // $ MISSING: Alert + + const execAsync = promisify(cp.exec.bind(cp)); + execAsync(code); // $ MISSING: Alert + + const promisifiedCp = promisifyAll(cp); + promisifiedCp.exec(code); // $ MISSING: Alert + promisifiedCp.execFile(code); // $ MISSING: Alert + promisifiedCp.spawn(code); // $ MISSING: Alert +});