Skip to solution
easyPhone Screen

What are the main security risks of using the 'eval()' function in Node.js?

811 views
01

Understand the problem

Question presented to candidate: "A code review flags eval(userInput) inside an API handler. Walk through exactly what an attacker could do with that, concretely, not just 'it's dangerous.'"

What a strong answer should cover:

  • eval(str) executes str as arbitrary JavaScript, with full access to the surrounding scope — not a sandboxed, restricted evaluation of "just an expression." Anything the calling code could do, the evaluated string can also do.
  • 📌 A concrete, demonstrated consequence, not a hypothetical one: code passing user input to eval() can be made to read variables in the enclosing closure it was never given access to, call require() to load arbitrary modules (including child_process to run OS commands), and even reassign an outer-scope variable — genuinely mutating state outside the function's own scope.
  • This is a form of code injection, the same class of vulnerability as SQL injection, just for the JavaScript language itself rather than a query language — untrusted input is being interpreted as code rather than treated purely as data.
  • eval() also defeats most static analysis and minification/bundling optimizations — a bundler cannot safely tree-shake or rename anything that might be referenced by a dynamically-evaluated string, which is a real, separate cost even in a codebase with no malicious input at all.
  • The standard, correct alternatives depend on the actual need: JSON.parse for parsing data (never eval for this — a classic, real historical mistake before JSON.parse was standard); a proper expression parser/sandboxed evaluation library for genuinely needing to evaluate a restricted user-supplied formula; or simply restructuring the code so no string ever needs to become executable code at all.
  • new Function(str) and vm.runInNewContext are related, sometimes-confused mechanisms: new Function still executes arbitrary code (with a different, more limited scope than eval, but still not safe for untrusted input); Node's built-in vm module offers a genuine, deliberately-scoped sandbox, though it is not a complete, airtight security boundary either and needs careful, correct configuration.

Clarifying questions expected:

  • "Is the input ever attacker-controlled, even indirectly, or is it fully trusted internal data?" — the entire risk hinges on this.
  • "Is the actual need 'evaluate a small user-supplied math expression' or something broader?" — decides whether a restricted expression parser is a sufficient, safer substitute.

Code / implementation expected: Yes — actually demonstrating eval reading and mutating outer scope, and calling require(), is the concrete, convincing version of this answer, not an abstract warning.

securitybest-practiceseval
02

Attempt it yourself

Sketch your approach before reading the solution — that's what interviews test.

Nudge consolestandby

Stuck? Beam a request up — the console returns a conceptual nudge that guides your logic without spoiling the implementation.

03

Study the solution

Target Audience: Engineers preparing for Node.js security-focused phone screens — no prior security background assumed. Difficulty: Easy

How to read this doc: Concepts are explained in plain language first, then tagged with 📌 Interview term:. Every consequence below was **actually demonstra

Solution ready — 2 min read

Classified // press E to declassify

04

Read the code

A real, run demonstration of eval() reading, mutating, and using require() from inside an evaluated string
let secret = "super-secret-value";

function processUserInput(expr) {
  return eval(expr); // NEVER do this with untrusted input — demonstration only
}

console.log(processUserInput("2+2"));
// 4 — the "intended" calculator use

console.log(processUserInput("secret"));
// super-secret-value — read a variable it was never given access to

console.log(processUserInput('require("os").platform()'));
// win32 — loaded and called an arbitrary module

processUserInput('secret = "OVERWRITTEN BY EVAL"');
console.log(secret);
// OVERWRITTEN BY EVAL — mutated the outer scope directly

// The correct alternative for data:
const data = JSON.parse('{"x": 1}'); // never eval() for this
05

Join the discussion

Discussion (0)

Sign in to join the discussion.

No responses yet. Be the first to share what you think.

Transmission complete // awaiting log

KEEP THE
STREAK ALIVE.

Dossier 11 of 152 decoded in the Node.js track. One more won't hurt.

Back to track