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 stringstras 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 accessobj[prop], a map of functions,Function()in a controlled case.
Quick example
eval("console.log('Hello from eval!')");
// output: Hello from eval!
const x = 10;
const y = 5;
console.log(eval('x + y')); // 15eval "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:
const x = 10;
const y = 5;
console.log(eval('x + y')); // 15Example 2, creating variables (dangerous):
eval('var z = 100;');
console.log(z); // 100The problem is that z is created in the current scope and may overwrite existing values.
Example 3, dynamic code (bad practice):
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.
const userInput = "alert('pwned')";
eval(userInput); // runs straight away in the browserInstead 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.
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
| Task | What to use instead |
|---|---|
| Evaluate a mathematical expression | Function() or a ready made expression parser |
| Parse JSON | JSON.parse() |
| Run dynamic code from a known set of functions | An object with a map of functions |
| Read a property by name | obj[propName], not eval('obj.' + propName) |
Replacement examples.
Bad:
eval("user.name = 'Tim'");Good:
user['name'] = 'Tim';Bad:
const obj = eval('(' + jsonStr + ')');Good:
const obj = JSON.parse(jsonStr);Bad:
eval('sum(5, 10)');Good:
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 ofobj[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 withoutunsafe-evalblocks it, and that is correct behaviour.
Quick recap
| Aspect | Verdict |
|---|---|
| What it does | Executes a string as JavaScript code |
| Security | Very dangerous: XSS and injections |
| Performance | Slow |
| Debugging | Hard |
| Optimisation | Blocks JIT |
| When to use | Only in very rare cases, when the string is fully under your control |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.