Never use eval(), new Function(), or vm.runInScript() with user-provided input. These functions execute arbitrary code with the full privileges of your Node.js process — an attacker can read files, access databases, or take over the entire server.
eval() and new Function() execute arbitrary JavaScript with the same permissions as your Node.js process. An attacker who controls the input to these functions can read environment variables (database credentials, API keys), access the filesystem, make network requests, or spawn child processes — achieving full remote code execution.
BeforeMerge scans your pull requests against this rule and 3+ others. Get actionable feedback before code ships.
eval(), new Function(), and vm.runInNewContext() compile and execute strings as JavaScript code. When user input reaches these functions, the attacker can execute arbitrary code with the full privileges of your Node.js process.
This is not a theoretical risk — it is the most severe vulnerability class (Remote Code Execution / RCE). An attacker who achieves RCE can:
process.env to steal database credentials, API keys, and secretsEven vm.runInNewContext() is not a sandbox — it can be escaped to access the host process.
Never use eval(), new Function(), vm.runInNewContext(), or setTimeout/setInterval with string arguments. If you need to parse structured data, use JSON.parse(). If you need dynamic behavior, use a lookup table or strategy pattern.
// eval with user input — full RCE
app.post("/calculate", (req, res) => {
const result = eval(req.body.expression); // Attacker sends: process.env.DATABASE_URL
res.json({ result });
});
// new Function with user input — same risk
const fn = new Function("return " + req.body.formula);
// setTimeout with string — evaluates as code
setTimeout("alert(' + userInput + ')", 1000);// Safe math evaluation with a parser library
import { evaluate } from "mathjs";
app.post("/calculate", (req, res) => {
const result = evaluate(req.body.expression); // Only evaluates math
res.json({ result });
});
// Strategy pattern instead of dynamic code
const operations: Record<string, (a: number, b: number) => number> = {
add: (a, b) => a + b,
subtract: (a, b) => a - b,
multiply: (a, b) => a * b,
};
app.post("/calculate", (req, res) => {
const { operation, a, b } = req.body;
const fn = operations[operation];
if (!fn) return res.status(400).json({ error: "Unknown operation" });
res.json({ result: fn(a, b) });
});Search for eval and dynamic code execution:
grep -rn 'eval(\|new Function(\|vm\.run\|setTimeout(\s*[\x27"]' --include="*.ts" --include="*.js"eval, new Function, vm.run, and string-argument setTimeout/setIntervalJSON.parse() with a try/catchno-eval and no-new-func to prevent future usage