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)executesstras 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, callrequire()to load arbitrary modules (includingchild_processto 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.parsefor parsing data (neverevalfor this — a classic, real historical mistake beforeJSON.parsewas 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)andvm.runInNewContextare related, sometimes-confused mechanisms:new Functionstill executes arbitrary code (with a different, more limited scope thaneval, but still not safe for untrusted input); Node's built-invmmodule 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.