Skip to main content

Why eval is dangerous

eval() is a built in function that takes a string and makes the JavaScript engine execute it as ordinary code. It is one of the most dangerous and most disputed functions in the language, because it erases the boundary between data and code, so it should almost always be replaced with something safer.

Theory

TL;DR

  • eval(str) runs the contents of the string str as JavaScript code and returns the value of the last expression.
  • The main problem is security: an uncontrolled string means arbitrary code execution, XSS and injections.
  • Performance drops, because the engine cannot analyse and optimise such code in advance (JIT is blocked).
  • eval() runs in the current scope, so it can create and overwrite the variables around it.
  • Almost every real task has a replacement: JSON.parse(), key access obj[prop], a map of functions, Function() in a controlled case.

Quick example

javascript
eval("console.log('Hello from eval!')"); // output: Hello from eval! const x = 10; const y = 5; console.log(eval('x + y')); // 15

eval "understands" that the string 'x + y' is an expression, evaluates it in the current scope and returns the result.

What eval actually does

eval() does not parse a formula and has no sandbox of its own: it hands the string to the very same engine that runs the rest of your code, with the very same privileges.

Example 1, evaluating an expression:

javascript
const x = 10; const y = 5; console.log(eval('x + y')); // 15

Example 2, creating variables (dangerous):

javascript
eval('var z = 100;'); console.log(z); // 100

The problem is that z is created in the current scope and may overwrite existing values.

Example 3, dynamic code (bad practice):

javascript
function runCode(code) { eval(code); } runCode("alert('running arbitrary code')");

This executes any code passed as a string. If that string came from a user, you get an XSS attack or a full takeover of the application.

Security risk (XSS and injections)

eval() executes any code it is given, including malicious code typed in by a user or an attacker.

javascript
const userInput = "alert('pwned')"; eval(userInput); // runs straight away in the browser

Instead of alert that code could read document.cookie, localStorage or a session token and send them to a third party server. This is a direct path to XSS and data leaks. That is why Content Security Policy blocks eval() by default unless unsafe-eval is allowed.

Worse performance

Code inside eval() runs more slowly, because the engine cannot optimise it: it does not know in advance what will be there. Every eval() call forces the engine to parse and interpret the string again, and a function that contains eval() often loses JIT optimisations entirely, because the engine cannot prove which variables it uses.

It breaks scoping

Code inside eval() can create or change variables of the current context, which makes the program unpredictable and hard to debug.

javascript
let a = 10; eval('a = 99;'); console.log(a); // 99, the value changed "from the inside"

In strict mode ('use strict') the situation is a little better: eval() gets its own scope for declarations, so a var inside it no longer leaks out. It can still read and overwrite existing variables though.

Hard to read and to maintain

eval() makes the code "magic": until it runs, you do not know what will be executed. Linters and static analysis see nothing inside the string, editor autocomplete and symbol renaming do not work, and stack traces point at generated code instead of a readable place in a file.

Safe alternatives

TaskWhat to use instead
Evaluate a mathematical expressionFunction() or a ready made expression parser
Parse JSONJSON.parse()
Run dynamic code from a known set of functionsAn object with a map of functions
Read a property by nameobj[propName], not eval('obj.' + propName)

Replacement examples.

Bad:

javascript
eval("user.name = 'Tim'");

Good:

javascript
user['name'] = 'Tim';

Bad:

javascript
const obj = eval('(' + jsonStr + ')');

Good:

javascript
const obj = JSON.parse(jsonStr);

Bad:

javascript
eval('sum(5, 10)');

Good:

javascript
const actions = { sum: (a, b) => a + b }; actions['sum'](5, 10);

Common mistakes

  • Believing new Function(...) is safe. It also compiles a string into code, just in the global scope, so for untrusted input it is just as dangerous.
  • Using eval() to parse JSON. It is both slower and unsafe; JSON.parse() exists exactly for this.
  • Building a property name as a string: eval('obj.' + key) instead of obj[key]. The second version is shorter, faster and safe.
  • Thinking that sanitising the string makes eval() safe. Reliably escaping arbitrary JavaScript is practically impossible.
  • Forgetting the hidden forms of eval: a string as the first argument of setTimeout('doWork()', 100) is executed the same way.
  • Being surprised that eval() does not work in production: a CSP without unsafe-eval blocks it, and that is correct behaviour.

Quick recap

AspectVerdict
What it doesExecutes a string as JavaScript code
SecurityVery dangerous: XSS and injections
PerformanceSlow
DebuggingHard
OptimisationBlocks JIT
When to useOnly in very rare cases, when the string is fully under your control

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.