Improper Neutralization of Directives in Dynamically Evaluated Code ('Eval Injection')
Description
Eval Injection is a specific variant of code injection that occurs when software receives input from an upstream component and evaluates it as code using functions such as eval(), exec(), Function(), or equivalent constructs without properly neutralizing code directives. The vulnerability exists in many programming languages: Python's eval()/exec(), PHP's eval(), JavaScript's eval()/Function(), Ruby's eval(), and Perl's eval(). When user-controlled data reaches these functions, attackers can execute arbitrary code in the context of the interpreter, gaining full access to the application's capabilities and potentially compromising the underlying system.
Risk
Eval injection provides attackers with direct code execution capabilities, representing a critical security risk. Since evaluated code runs with the same privileges as the application, attackers can access sensitive data, modify application behavior, read and write files, make network connections, and potentially execute system commands. In web applications, this typically leads to complete server compromise. JavaScript eval injection in client-side code can lead to XSS attacks, while server-side eval injection in Node.js applications enables remote code execution. The vulnerability is particularly insidious because developers sometimes use eval for seemingly benign purposes like dynamic configuration or mathematical calculations, not realizing the security implications.
Solution
Eliminate the use of eval() and similar functions entirely. For mathematical expressions, use dedicated safe expression parsers (e.g., ast.literal_eval() in Python for literals, or specialized math parsing libraries). For JSON parsing, use native JSON parsers (JSON.parse(), json.loads()). For dynamic functionality, use safe alternatives like lookup tables, factory patterns, or configuration files. If eval cannot be avoided, implement strict allowlist validation that only permits known-safe values. Consider using sandboxed execution environments for truly dynamic code requirements. In JavaScript, avoid eval(), Function(), setTimeout() with strings, and setInterval() with strings.
Common Consequences
| Impact | Details |
|---|---|
| Confidentiality | Scope: Confidentiality Arbitrary code execution enables access to all application data, environment variables, filesystem contents, and network resources. |
| Integrity | Scope: Integrity Attackers can modify data, alter application logic, inject backdoors, and manipulate system state through executed code. |
| Availability | Scope: Availability Malicious code can crash applications, consume resources, delete files, or render systems unusable. |
| Access Control | Scope: Complete Compromise Eval injection typically results in full application compromise with all privileges of the running process. |
Example Code + Solution Code
Vulnerable Code
// VULNERABLE: JavaScript eval() with user input
app.get('/calc', (req, res) => {
const expression = req.query.expr;
// Attack: expr=require('child_process').execSync('cat /etc/passwd')
const result = eval(expression);
res.send(`Result: ${result}`);
});
// VULNERABLE: Function constructor
const userFunc = req.query.func;
const dynamicFunc = new Function(userFunc); // Same as eval
dynamicFunc();
// VULNERABLE: setTimeout with string
setTimeout("alert(" + userInput + ")", 1000);
# VULNERABLE: Python eval()
user_input = request.args.get('calc')
# Attack: __import__('os').system('id')
result = eval(user_input)
# VULNERABLE: exec()
code = request.form.get('code')
exec(code) # Arbitrary code execution
Fixed Code
// SAFE: Use math expression parser instead of eval
const mathjs = require('mathjs');
app.get('/calc', (req, res) => {
const expression = req.query.expr || '';
// Validate allowed characters
if (!/^[\d\s+\-*/().]+$/.test(expression)) {
return res.status(400).send('Invalid expression');
}
try {
// mathjs safely parses mathematical expressions
const result = mathjs.evaluate(expression);
res.send(`Result: ${result}`);
} catch (e) {
res.status(400).send('Invalid expression');
}
});
// SAFE: Use lookup tables instead of dynamic function creation
const allowedOperations = {
'add': (a, b) => a + b,
'subtract': (a, b) => a - b,
'multiply': (a, b) => a * b,
'divide': (a, b) => b !== 0 ? a / b : null
};
app.get('/operation', (req, res) => {
const op = req.query.op;
const a = parseFloat(req.query.a);
const b = parseFloat(req.query.b);
if (!(op in allowedOperations) || isNaN(a) || isNaN(b)) {
return res.status(400).send('Invalid parameters');
}
const result = allowedOperations[op](a, b);
res.send(`Result: ${result}`);
});
# SAFE: Use ast.literal_eval for safe literal evaluation
import ast
def safe_literal_eval(expression):
"""Only evaluate Python literals (strings, numbers, tuples, lists, dicts)"""
try:
return ast.literal_eval(expression)
except (ValueError, SyntaxError):
raise ValueError("Invalid literal expression")
# For math expressions, use a safe parser
def safe_math_eval(expression):
allowed_chars = set('0123456789+-*/().e ')
if not all(c in allowed_chars for c in expression):
raise ValueError("Invalid characters")
# Parse AST and only allow safe operations
tree = ast.parse(expression, mode='eval')
# ... implement safe evaluation as in CWE-94 example
Exploited in the Wild
Server-Side JavaScript Injection (Node.js Applications, Ongoing)
Eval injection vulnerabilities in Node.js applications have been exploited to achieve remote code execution on server systems. Calculator widgets, expression evaluators, and dynamic configuration handlers are common attack vectors.
MongoDB NoSQL Injection via $where (Database Applications, Ongoing)
MongoDB's $where operator allows JavaScript execution in queries, which when combined with user input enables eval-style injection attacks against database systems.
Tools to test/exploit
-
Burp Suite — web security testing platform with capabilities for detecting eval injection vulnerabilities.
-
NoSQLMap — automated testing tool for NoSQL injection including JavaScript eval injection.
CVE Examples
-
CVE-2023-26136 — tough-cookie eval injection through prototype pollution.
-
CVE-2022-21824 — Node.js prototype pollution enabling eval injection.
References
-
MITRE. "CWE-95: Improper Neutralization of Directives in Dynamically Evaluated Code." https://cwe.mitre.org/data/definitions/95.html
-
OWASP. "Code Injection." https://owasp.org/www-community/attacks/Code_Injection