Skip to content

Commit 2a7ca88

Browse files
committed
Add end2end test for code injection using new Function(...)
1 parent 768162e commit 2a7ca88

File tree

2 files changed

+58
-20
lines changed

2 files changed

+58
-20
lines changed

end2end/tests/express-mongodb.test.js

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ t.test("it blocks in blocking mode", (t) => {
2121
});
2222

2323
server.on("error", (err) => {
24-
t.fail(err.message);
24+
t.fail(err);
2525
});
2626

2727
let stdout = "";
@@ -47,17 +47,27 @@ t.test("it blocks in blocking mode", (t) => {
4747
fetch("http://127.0.0.1:4000/?search=title", {
4848
signal: AbortSignal.timeout(5000),
4949
}),
50+
fetch("http://127.0.0.1:4000/hello/hans", {
51+
signal: AbortSignal.timeout(5000),
52+
}),
53+
fetch(`http://127.0.0.1:4000/hello/${encodeURIComponent(`hans" //`)}`, {
54+
signal: AbortSignal.timeout(5000),
55+
}),
5056
]);
5157
})
52-
.then(([noSQLInjection, jsInjection, normalSearch]) => {
53-
t.equal(noSQLInjection.status, 500);
54-
t.equal(jsInjection.status, 500);
55-
t.equal(normalSearch.status, 200);
56-
t.match(stdout, /Starting agent/);
57-
t.match(stderr, /Zen has blocked a NoSQL injection/);
58-
})
58+
.then(
59+
([noSQLInjection, jsInjection, normalSearch, safeName, unsafeName]) => {
60+
t.equal(noSQLInjection.status, 500);
61+
t.equal(jsInjection.status, 500);
62+
t.equal(normalSearch.status, 200);
63+
t.equal(safeName.status, 200);
64+
t.equal(unsafeName.status, 500);
65+
t.match(stdout, /Starting agent/);
66+
t.match(stderr, /Zen has blocked a NoSQL injection/);
67+
}
68+
)
5969
.catch((error) => {
60-
t.fail(error.message);
70+
t.fail(error);
6171
})
6272
.finally(() => {
6373
server.kill();
@@ -96,17 +106,27 @@ t.test("it does not block in dry mode", (t) => {
96106
fetch("http://127.0.0.1:4001/?search=title", {
97107
signal: AbortSignal.timeout(5000),
98108
}),
109+
fetch("http://127.0.0.1:4001/hello/hans", {
110+
signal: AbortSignal.timeout(5000),
111+
}),
112+
fetch(`http://127.0.0.1:4001/hello/${encodeURIComponent(`hans" //`)}`, {
113+
signal: AbortSignal.timeout(5000),
114+
}),
99115
])
100116
)
101-
.then(([noSQLInjection, jsInjection, normalSearch]) => {
102-
t.equal(noSQLInjection.status, 200);
103-
t.equal(jsInjection.status, 200);
104-
t.equal(normalSearch.status, 200);
105-
t.match(stdout, /Starting agent/);
106-
t.notMatch(stderr, /Zen has blocked a NoSQL injection/);
107-
})
117+
.then(
118+
([noSQLInjection, jsInjection, normalSearch, safeName, unsafeName]) => {
119+
t.equal(noSQLInjection.status, 200);
120+
t.equal(jsInjection.status, 200);
121+
t.equal(normalSearch.status, 200);
122+
t.equal(safeName.status, 200);
123+
t.equal(unsafeName.status, 200);
124+
t.match(stdout, /Starting agent/);
125+
t.notMatch(stderr, /Zen has blocked a NoSQL injection/);
126+
}
127+
)
108128
.catch((error) => {
109-
t.fail(error.message);
129+
t.fail(error);
110130
})
111131
.finally(() => {
112132
server.kill();
@@ -141,7 +161,7 @@ t.test("it blocks in blocking mode (with open telemetry enabled)", (t) => {
141161
});
142162

143163
server.on("error", (err) => {
144-
t.fail(err.message);
164+
t.fail(err);
145165
});
146166

147167
let stdout = "";
@@ -174,7 +194,7 @@ t.test("it blocks in blocking mode (with open telemetry enabled)", (t) => {
174194
t.match(stderr, /Zen has blocked a NoSQL injection/);
175195
})
176196
.catch((error) => {
177-
t.fail(error.message);
197+
t.fail(error);
178198
})
179199
.finally(() => {
180200
server.kill("SIGINT");
@@ -237,7 +257,7 @@ t.test("it does not block in dry mode (with open telemetry enabled)", (t) => {
237257
t.notMatch(stderr, /Zen has blocked a NoSQL injection/);
238258
})
239259
.catch((error) => {
240-
t.fail(error.message);
260+
t.fail(error);
241261
})
242262
.finally(() => {
243263
server.kill("SIGINT");

sample-apps/express-mongodb/app.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,24 @@ async function main(port) {
186186
})
187187
);
188188

189+
app.get(
190+
"/hello/:name",
191+
asyncHandler(async (req, res) => {
192+
const { name } = req.params;
193+
194+
if (!name) {
195+
return res.status(400).end();
196+
}
197+
198+
// This code is vulnerable to code injection
199+
// This is just a sample app to demonstrate the vulnerability
200+
// Do not use this code in production
201+
const welcome = new Function(`return "Hello, your name is ${name}!"`);
202+
203+
res.send(welcome());
204+
})
205+
);
206+
189207
return new Promise((resolve, reject) => {
190208
try {
191209
app.listen(port, () => {

0 commit comments

Comments
 (0)