What it is: Eval Injection (CWE-95) is a type of code injection vulnerability that occurs when an application passes untrusted input into a dynamic code evaluation function like eval() without neutralizing code syntax.
Why it matters: Unlike most injection types that target a downstream interpreter, this directly compiles and runs attacker input as code in the application's own language runtime, typically with full application-level privileges.
How to fix it: Refactor to avoid dynamic evaluation entirely, using a purpose-built parser or restricted evaluator for the specific use case instead.
TL;DR: Eval Injection lets an attacker run arbitrary code by getting untrusted input into a dynamic evaluation function like eval(); the fix is avoiding eval() entirely in favor of a safe, purpose-built parser for the actual use case.
| Field | Value |
|---|---|
| CWE ID | CWE-95 |
| OWASP Category | A05:2025 - Injection |
| CAPEC | CAPEC-35 |
| Typical Severity | Critical |
| Affected Technologies | Python, JavaScript/Node.js, PHP, Ruby, and other languages with dynamic evaluation functions |
| Detection Difficulty | Easy |
| Last Updated | 2026-07-27 |
What is Eval Injection?
Improper Neutralization of Directives in Dynamically Evaluated Code (‘Eval Injection’) (CWE-95) is a type of code injection vulnerability that occurs when a product receives input from an upstream component but does not neutralize code syntax before using the input in a dynamic evaluation call (e.g. eval). As defined by the MITRE Corporation under CWE-95, and classified by the OWASP Foundation under A05:2025 - Injection, this weakness has a Medium likelihood of exploit and is a direct child of the broader Code Injection weakness (CWE-94).
Quick Summary
Most injection vulnerabilities smuggle malicious syntax into a downstream interpreter running as a separate process or component. Eval Injection is more direct: the untrusted input is handed straight to the application’s own language runtime and compiled as real, executable code, running with whatever privileges the application itself already has.
Jump to: Quick Summary · Eval Injection Overview · How Eval Injection Works · Business Impact of Eval Injection · Eval Injection Attack Scenario · How to Detect Eval Injection · How to Fix Eval Injection · Framework-Specific Fixes for Eval Injection · How to Ask AI to Check Your Code for Eval Injection · Eval Injection Best Practices Checklist · Eval Injection FAQ · Vulnerabilities Related to Eval Injection · References · Scan Your Own Site
Eval Injection Overview
What: Untrusted input is passed to a dynamic code evaluation function (eval(), Function(), or equivalent) without neutralizing code syntax.
Why it matters: The injected content executes directly in the application’s own runtime, typically with the full privileges of the application process.
Where it occurs: Any feature that dynamically evaluates a string built from or containing user input — often used as a shortcut for parsing expressions, deserializing data, or implementing plugin-like extensibility.
Who is affected: Applications that pass untrusted input, directly or indirectly, into eval() or similar dynamic-evaluation constructs.
Who is NOT affected: Applications that avoid dynamic evaluation of untrusted input entirely, using dedicated parsers or restricted evaluators instead.
How Eval Injection Works
Root Cause
The application passes untrusted input into a dynamic code evaluation function without neutralizing code-syntax elements, letting the input execute as real code.
Attack Flow
- The attacker identifies a feature that evaluates user input dynamically (e.g. a “custom formula” or expression field).
- The attacker submits a value containing real code rather than the expected simple expression.
- The application passes this directly to
eval()or an equivalent function. - The language runtime compiles and executes the attacker’s code as if it were part of the application itself.
- The attacker’s code runs with the application’s own privileges, potentially reading files, making network calls, or altering application state.
Prerequisites to Exploit
- Untrusted input reaches a dynamic code evaluation function.
- The application does not neutralize or restrict the code syntax before evaluation.
- The evaluation runs with meaningful privileges the attacker wants to leverage.
Vulnerable Code
def calculate(expression):
return eval(expression)
expression is passed directly to eval() with no restriction at all, so a value like __import__('os').system('rm -rf /tmp/data') executes as real Python code instead of a simple arithmetic expression.
Secure Code
import ast
import operator
_OPS = {ast.Add: operator.add, ast.Sub: operator.sub, ast.Mult: operator.mul, ast.Div: operator.truediv}
def calculate(expression):
tree = ast.parse(expression, mode="eval")
return _eval_node(tree.body)
def _eval_node(node):
if isinstance(node, ast.Constant):
return node.value
if isinstance(node, ast.BinOp) and type(node.op) in _OPS:
return _OPS[type(node.op)](_eval_node(node.left), _eval_node(node.right))
raise ValueError("Unsupported expression")
Instead of calling eval() at all, the expression is parsed into an AST and evaluated using an explicit allowlist of permitted operations, so no arbitrary code can ever execute regardless of what the input contains.
Business Impact of Eval Injection
Confidentiality: Injected code can access restricted data and files reachable by the application process.
Integrity: Nearly all code injection attacks compromise data integrity, since the control-plane data injected is incidental to normal data recall or writing.
Availability: Injected code can crash the application or consume excessive resources.
Non-Repudiation: Actions performed by injected code are often unlogged, since the application’s normal audit logging doesn’t anticipate arbitrary code execution.
- Full application-level compromise, since injected code runs with the application’s own privileges
- Access Control bypass, since injected code can access resources the attacker is otherwise directly prevented from reaching
Eval Injection Attack Scenario
- An attacker finds a “custom formula” feature in a spreadsheet-like application that evaluates user-submitted expressions with
eval(). - They submit a formula string containing a Python import and system call instead of a simple arithmetic expression.
- The application’s
eval()call compiles and executes the malicious code with the application’s own privileges. - The attacker’s injected code reads sensitive files or establishes a reverse shell, achieving full server compromise.
How to Detect Eval Injection
Manual Testing
- Search the codebase for
eval(),Function(),exec(), or equivalent dynamic-evaluation constructs. - Trace whether any untrusted input reaches their argument.
- Submit a harmless code-execution proof (e.g. a value that would produce a distinctive, observable side effect) to confirm actual execution.
Automated Scanners (SAST / DAST)
Static analysis can flag eval()-family calls fed with variables traceable to untrusted input directly in source, while dynamic testing with a safe proof-of-execution payload confirms whether the live application actually executes injected code.
PenScan Detection
PenScan’s scanner engines test inputs that could reach a dynamic code evaluation call with real, safe detection payloads.
False Positive Guidance
An eval()-family call fed only with hardcoded, developer-controlled strings (never user input) is not vulnerable regardless of how the function itself looks — confirm the actual data flow before treating a code-search match as a real finding.
How to Fix Eval Injection
- Refactor to avoid dynamic evaluation of untrusted input entirely wherever possible.
- Use a purpose-built, restricted parser for the specific use case (arithmetic expressions, JSON, templating) instead of a general-purpose
eval(). - If dynamic evaluation truly cannot be avoided, use the most restrictive safe alternative available (e.g. Python’s
ast.literal_eval()for literal data only) and still validate input against a strict allowlist.
Framework-Specific Fixes for Eval Injection
- Python: replace
eval()withast.literal_eval()for literal data, or a restricted AST-based evaluator for expressions, as shown above. - Node.js: avoid
eval()and theFunction()constructor entirely; useJSON.parse()for data and a dedicated expression-parsing library for formulas. - PHP: avoid
eval()entirely; usejson_decode()for data and a dedicated template/expression engine for dynamic logic. - Ruby: avoid
eval()/instance_eval()on untrusted input; use a restricted DSL or parser library for the specific use case.
How to Ask AI to Check Your Code for Eval Injection
Review the following [language] code block for potential CWE-95 Eval Injection vulnerabilities and rewrite it to avoid dynamic code evaluation, using a restricted parser or allowlist-based evaluator instead: [paste code here]
Eval Injection Best Practices Checklist
✅ Avoid dynamic evaluation of untrusted input entirely wherever possible ✅ Use a purpose-built, restricted parser for the specific use case ✅ Use the most restrictive safe alternative if evaluation truly can’t be avoided ✅ Validate input against a strict allowlist as defense-in-depth
Eval Injection FAQ
How does Eval Injection let an attacker run arbitrary code?
If untrusted input is passed directly to a function like eval() that dynamically parses and executes a string as code, the attacker’s input is not treated as data at all — it is compiled and run with the full capability of the host language.
How likely is Eval Injection to be exploited according to MITRE?
MITRE rates the likelihood of exploit for this weakness as Medium, reflecting that eval() calls on untrusted input are less common than, say, SQL string concatenation, but the impact when found is typically maximal.
How is Eval Injection different from OS Command Injection?
OS Command Injection targets a shell interpreter running outside the application process; Eval Injection targets the application’s own language runtime directly via a dynamic evaluation function, which can be even more dangerous since it runs with the full permissions of the application itself.
How do I detect Eval Injection in my own application?
Search the codebase directly for eval(), Function(), exec(), or equivalent dynamic-evaluation calls, and trace whether any untrusted input reaches their argument.
How do I fix Eval Injection without eval() at all?
Refactor the code to avoid dynamic evaluation entirely — most use cases (parsing simple expressions, deserializing data) have a safe, purpose-built alternative like a JSON parser or a restricted expression evaluator.
How does Python’s ast.literal_eval() differ from eval() for this purpose?
ast.literal_eval() only parses Python literals (strings, numbers, lists, dicts) and never executes arbitrary code, making it a much safer choice than eval() when the goal is just parsing simple data structures — though it should still not be used on fully untrusted input due to potential resource-consumption issues with deeply nested structures.
How can PenScan help find Eval Injection?
PenScan tests inputs that could reach a dynamic code evaluation call with real, safe detection payloads to confirm whether injected code actually executes.
Vulnerabilities Related to Eval Injection
| CWE | Name | Relationship |
|---|---|---|
| CWE-94 | Improper Control of Generation of Code (‘Code Injection’) | ChildOf |
References
Scan Your Own Site
Manual code review catches what you know to look for. An automated scan catches what you didn’t. Scan your own website using PenScan to find Eval Injection and other risks before an attacker does.