Skip to content

Commit c8cf958

Browse files
committed
add test cases for js/shell-command-constructed-from-input
1 parent 59001bb commit c8cf958

File tree

9 files changed

+726
-0
lines changed

9 files changed

+726
-0
lines changed

javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction.expected

Lines changed: 416 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Security/CWE-078/UnsafeShellCommandConstruction.ql

javascript/ql/test/query-tests/Security/CWE-078/UselessUseOfCat.expected

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
readFile
2+
| lib/lib.js:71:2:71:32 | cp.exec ... + name) | fs.readFile("/foO/BAR/" + name) |
3+
| lib/lib.js:73:2:73:32 | cp.exec ... + "\\"") | fs.readFile(""" + name + """) |
4+
| lib/lib.js:75:2:75:30 | cp.exec ... + "'") | fs.readFile("'" + name + "'") |
5+
| lib/lib.js:77:2:77:38 | cp.exec ... + "'") | fs.readFile("'/foo/bar" + name + "'") |
26
| uselesscat.js:10:1:10:43 | exec("c ... ut) {}) | fs.readFile("foo/bar", function(err, out) {...}) |
37
| uselesscat.js:12:1:14:2 | exec("c ... ut);\\n}) | fs.readFile("/proc/" + id + "/status", function(err, out) {...}) |
48
| uselesscat.js:16:1:16:29 | execSyn ... uinfo') | fs.readFileSync("/proc/cpuinfo") |
@@ -89,6 +93,9 @@ options
8993
| child_process-test.js:53:5:53:59 | cp.spaw ... cmd])) | child_process-test.js:53:25:53:58 | ['/C', ... , cmd]) |
9094
| child_process-test.js:54:5:54:50 | cp.spaw ... t(cmd)) | child_process-test.js:54:25:54:49 | ['/C', ... at(cmd) |
9195
| child_process-test.js:64:3:64:21 | cp.spawn(cmd, args) | child_process-test.js:64:17:64:20 | args |
96+
| lib/lib.js:152:2:152:23 | cp.spaw ... gs, cb) | lib/lib.js:152:21:152:22 | cb |
97+
| lib/lib.js:159:2:159:23 | cp.spaw ... gs, cb) | lib/lib.js:159:21:159:22 | cb |
98+
| lib/lib.js:163:2:167:2 | cp.spaw ... t' }\\n\\t) | lib/lib.js:166:3:166:22 | { stdio: 'inherit' } |
9299
| uselesscat.js:28:1:28:39 | execSyn ... 1000}) | uselesscat.js:28:28:28:38 | {uid: 1000} |
93100
| uselesscat.js:30:1:30:64 | exec('c ... t) { }) | uselesscat.js:30:26:30:38 | { cwd: './' } |
94101
| uselesscat.js:34:1:34:54 | execSyn ... utf8'}) | uselesscat.js:34:36:34:53 | {encoding: 'utf8'} |
Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
var cp = require("child_process")
2+
3+
module.exports = function (name) {
4+
cp.exec("rm -rf " + name); // NOT OK
5+
6+
cp.execFile(name, [name]); // OK
7+
cp.execFile(name, name); // OK
8+
};
9+
10+
module.exports.foo = function (name) {
11+
cp.exec("rm -rf " + name); // NOT OK
12+
}
13+
14+
module.exports.foo.bar = function (name) {
15+
cp.exec("rm -rf " + name); // NOT OK
16+
}
17+
18+
function cla() { }
19+
cla.prototype.method = function (name) {
20+
cp.exec("rm -rf " + name); // NOT OK
21+
}
22+
module.exports = new cla();
23+
24+
25+
function cla2() { }
26+
cla2.prototype.method = function (name) {
27+
cp.exec("rm -rf " + name); // NOT OK
28+
}
29+
module.exports.bla = new cla2();
30+
31+
module.exports.lib2 = require("./lib2.js")
32+
33+
class Cla3 {
34+
constructor(name) {
35+
cp.exec("rm -rf " + name); // NOT OK
36+
}
37+
static foo(name) {
38+
cp.exec("rm -rf " + name); // NOT OK
39+
}
40+
bar(name) {
41+
cp.exec("rm -rf " + name); // NOT OK
42+
43+
cp.exec("rm -rf " + notASource); // OK
44+
}
45+
}
46+
47+
module.exports.cla3 = Cla3;
48+
49+
module.exports.mz = function (name) {
50+
require("mz/child_process").exec("rm -rf " + name); // NOT OK.
51+
}
52+
53+
module.exports.flow = function (name) {
54+
var cmd1 = "rm -rf " + name;
55+
cp.exec(cmd1); // NOT OK.
56+
57+
var cmd2 = "rm -rf " + name;
58+
function myExec(cmd) {
59+
cp.exec(cmd); // NOT OK.
60+
}
61+
myExec(cmd2);
62+
}
63+
64+
module.exports.stringConcat = function (name) {
65+
cp.exec("rm -rf " + name); // NOT OK.
66+
67+
cp.exec(name); // OK.
68+
69+
cp.exec("for foo in (" + name + ") do bla end"); // OK.
70+
71+
cp.exec("cat /foO/BAR/" + name) // NOT OK.
72+
73+
cp.exec("cat \"" + name + "\"") // NOT OK.
74+
75+
cp.exec("cat '" + name + "'") // NOT OK.
76+
77+
cp.exec("cat '/foo/bar" + name + "'") // NOT OK.
78+
79+
cp.exec(name + " some file") // OK.
80+
}
81+
82+
module.exports.arrays = function (name) {
83+
cp.exec("rm -rf " + name); // NOT OK.
84+
85+
var args1 = ["node"];
86+
args1.push(name);
87+
cp.exec(args1.join(" ")); // NOT OK.
88+
89+
cp.exec(["rm -rf", name].join(" ")); // NOT OK.
90+
91+
cp.exec(["rm -rf", "\"" + name + "\""].join(" ")); // NOT OK.
92+
93+
cp.execFile("rm", ["-rf", name]); // OK
94+
}
95+
96+
var util = require("util");
97+
module.exports.format = function (name) {
98+
cp.exec(util.format("rm -rf %s", name)); // NOT OK
99+
100+
cp.exec(util.format("rm -rf '%s'", name)); // NOT OK
101+
102+
cp.exec(util.format("rm -rf '/foo/bar/%s'", name)); // NOT OK
103+
104+
cp.exec(util.format("%s foo/bar", name)); // OK
105+
106+
cp.exec(util.format("for foo in (%s) do bar end", name)); // OK
107+
108+
cp.exec(require("printf")('rm -rf %s', name)); // NOT OK
109+
}
110+
111+
module.exports.valid = function (name) {
112+
cp.exec("rm -rf " + name); // NOT OK
113+
114+
if (!isValidName(name)) {
115+
return;
116+
}
117+
cp.exec("rm -rf " + name); // OK
118+
}
119+
120+
module.exports.safe = function (name) {
121+
cp.exec("rm -rf " + name); // NOT OK
122+
123+
if (!isSafeName(name)) {
124+
return;
125+
}
126+
cp.exec("rm -rf " + name); // OK
127+
}
128+
129+
class Cla4 {
130+
wha(name) {
131+
cp.exec("rm -rf " + name); // NOT OK
132+
}
133+
134+
static bla(name) {
135+
cp.exec("rm -rf " + name); // OK - not exported
136+
}
137+
constructor(name) {
138+
cp.exec("rm -rf " + name); // OK - not exported
139+
}
140+
}
141+
module.exports.cla4 = new Cla4();
142+
143+
function Cla5(name) {
144+
cp.exec("rm -rf " + name); // OK - not exported
145+
}
146+
module.exports.cla5 = new Cla5();
147+
148+
module.exports.indirect = function (name) {
149+
let cmd = "rm -rf " + name;
150+
let sh = "sh";
151+
let args = ["-c", cmd];
152+
cp.spawn(sh, args, cb); // NOT OK
153+
}
154+
155+
module.exports.indirect2 = function (name) {
156+
let cmd = name;
157+
let sh = "sh";
158+
let args = ["-c", cmd];
159+
cp.spawn(sh, args, cb); // OK
160+
161+
let cmd2 = "rm -rf " + name;
162+
var args2 = [cmd2];
163+
cp.spawn(
164+
'cmd.exe',
165+
['/C', editor].concat(args2),
166+
{ stdio: 'inherit' }
167+
);
168+
}
169+
170+
module.exports.cmd = function (command, name) {
171+
cp.exec("fo | " + command); // OK
172+
173+
cp.exec("fo | " + name); // NOT OK
174+
175+
}
176+
177+
module.exports.sanitizer = function (name) {
178+
var sanitized = "'" + name.replace(/'/g, "'\\''") + "'"
179+
cp.exec("rm -rf " + sanitized); // OK
180+
181+
var broken = "'" + name.replace(/'/g, "'\''") + "'"
182+
cp.exec("rm -rf " + broken); // NOT OK
183+
}
184+
185+
var path = require("path");
186+
module.exports.guard = function (name) {
187+
cp.exec("rm -rf " + name); // NOT OK
188+
189+
if (!path.exist(name)) {
190+
cp.exec("rm -rf " + name); // NOT OK
191+
return;
192+
}
193+
cp.exec("rm -rf " + name); // OK
194+
}
195+
196+
module.exports.blacklistOfChars = function (name) {
197+
cp.exec("rm -rf " + name); // NOT OK
198+
199+
if (/[^A-Za-z0-9_\/:=-]/.test(name)) {
200+
cp.exec("rm -rf " + name); // NOT OK
201+
} else {
202+
cp.exec("rm -rf " + name); // OK
203+
}
204+
}
205+
206+
module.exports.whitelistOfChars = function (name) {
207+
cp.exec("rm -rf " + name); // NOT OK
208+
209+
if (/^[A-Za-z0-9_\/:=-]$/.test(name)) {
210+
cp.exec("rm -rf " + name); // OK
211+
} else {
212+
cp.exec("rm -rf " + name); // NOT OK
213+
}
214+
}
215+
216+
module.exports.blackList2 = function (name) {
217+
cp.exec("rm -rf " + name); // NOT OK
218+
219+
if (!/^([a-zA-Z0-9]+))?$/.test(name)) {
220+
cp.exec("rm -rf " + name); // NOT OK
221+
process.exit(-1);
222+
}
223+
224+
cp.exec("rm -rf " + name); // OK - but FP due to tracking flow through `process.exit()`.
225+
}
226+
227+
module.exports.accessSync = function (name) {
228+
cp.exec("rm -rf " + name); // NOT OK
229+
230+
try {
231+
path.accessSync(name);
232+
} catch (e) {
233+
return;
234+
}
235+
236+
cp.exec("rm -rf " + name); // OK - but FP due to `path.accessSync` not being recognized as a sanitizer.
237+
}
238+
239+
var cleanInput = function (s) {
240+
if (/[^A-Za-z0-9_\/:=-]/.test(s)) {
241+
s = "'" + s.replace(/'/g, "'\\''") + "'";
242+
s = s.replace(/^(?:'')+/g, '') // unduplicate single-quote at the beginning
243+
.replace(/\\'''/g, "\\'"); // remove non-escaped single-quote if there are enclosed between 2 escaped
244+
}
245+
return s;
246+
}
247+
248+
module.exports.goodSanitizer = function (name) {
249+
cp.exec("rm -rf " + name); // NOT OK
250+
251+
var cleaned = cleanInput(name);
252+
253+
cp.exec("rm -rf " + cleaned); // OK
254+
}
255+
256+
var fs = require("fs");
257+
module.exports.guard2 = function (name) {
258+
cp.exec("rm -rf " + name); // NOT OK
259+
260+
if (!fs.existsSync("prefix/" + name)) {
261+
cp.exec("rm -rf prefix/" + name); // NOT OK
262+
return;
263+
}
264+
cp.exec("rm -rf prefix/" + name); // OK
265+
}
266+
267+
module.exports.sanitizerProperty = function (obj) {
268+
cp.exec("rm -rf " + obj.version); // NOT OK
269+
270+
obj.version = "";
271+
272+
cp.exec("rm -rf " + obj.version); // OK - but FP
273+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
var cp = require("child_process")
2+
3+
module.exports = function (name) {
4+
cp.exec("rm -rf " + name); // NOT OK - is imported from main module.
5+
};
6+
7+
module.exports.foo = function (name) {
8+
cp.exec("rm -rf " + name); // NOT OK - is imported from main module.
9+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
var cp = require("child_process")
2+
3+
module.exports = function (name) {
4+
cp.exec("rm -rf " + name); // OK, is not exported to a main-module.
5+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
var cp = require("child_process")
2+
3+
module.exports = function (name) {
4+
cp.exec("rm -rf " + name); // OK - this file belongs in a sub-"module", and is not the primary exported module.
5+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"name": "mySubLib",
3+
"version": "0.0.7",
4+
"main": "./index.js"
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"name": "myLib",
3+
"version": "0.0.7",
4+
"main": "./lib/lib.js"
5+
}

0 commit comments

Comments
 (0)