Code Injection
Improper Control of Generation of Code (Code Injection)
CWE-94 · Critical severity
What it is
CWE-94 exists when an application takes user input and treats it as code that the application then executes. Unlike OS command injection (which targets a shell), code injection targets the application's own interpreter: JavaScript eval, Python exec, Ruby eval, PHP eval, or any dynamic code path that compiles or evaluates strings at runtime.
Why it matters
Code injection grants remote code execution with the privileges of the application itself, with no intermediate shell to bypass. The pattern recurs in expression evaluators, formula calculators, template engines, plugin systems, and ad-hoc REPLs exposed to web users. Even where eval is not used directly, dynamic-import, Function constructor, indirect VM access (node:vm), and template strings with unescaped substitution can each be a code injection vector.
Common patterns
- eval(req.body.expr) or eval(req.query.code) anywhere in a request handler.
- new Function(userInput) to dynamically compile user-supplied code.
- Python exec or compile on data from a request, message queue, or database.
- Template engines used in eval-like mode (Jinja2 with autoescape disabled, server-side eval-style template tags).
- node:vm Script with un-vetted user input (sandbox escapes are common).
- JSON parsers implemented via eval (legacy code; CWE-915 overlap).
Languages affected
JavaScript, TypeScript, Python, Ruby, PHP
What Deva detects
Deva flags every call site that uses eval, new Function, setTimeout/setInterval with string arguments, node:vm.Script, node:vm.runInThisContext, Python exec, Python compile, Ruby instance_eval, Ruby class_eval, and PHP eval where the source data traces back to untrusted input. The scanner distinguishes safe constant-string uses (which it ignores) from variable-string uses (which it reports).
Example
Vulnerable
app.post('/calc', (req, res) => {
const result = eval(req.body.expr)
res.json({ result })
})Fixed
import { Parser } from 'expr-eval'
const calculator = new Parser({
operators: {
add: true, subtract: true, multiply: true, divide: true,
power: true, conditional: false, logical: false, comparison: false,
},
})
app.post('/calc', (req, res) => {
try {
const expr = String(req.body.expr || '').slice(0, 100)
const result = calculator.parse(expr).evaluate()
if (typeof result !== 'number' || !isFinite(result)) {
return res.status(400).json({ error: 'Bad expression' })
}
res.json({ result })
} catch {
res.status(400).json({ error: 'Bad expression' })
}
})The vulnerable version eval()s a request body. An attacker posting { expr: 'require("child_process").execSync("id")' } gets remote code execution. The fix uses expr-eval, a parser that supports a strict subset of arithmetic operators with no access to JavaScript globals. The input is also length-bounded and the result is type-checked. The pattern generalizes: never eval user input, always use a domain-specific parser with an explicit grammar.
Where this fits in OWASP Top 10
- A05 InjectionUntrusted input interpreted as code or commands by a downstream interpreter.
Compliance framework mapping
| Framework | Controls |
|---|---|
| OWASP Top 10:2025 | A05:2025 Injection |
| NIST 800-53 Rev 5 | SI-10 Information Input Validation, SC-18 Mobile Code |
| PCI-DSS v4.0.1 | 6.2.4 Software engineering techniques |
| CMMC L2 | SI.L2-3.14.1 Flaw remediation |
Related CWEs
Deva detects CWE-94 alongside its other CWE rules at write time, with AI-assisted fix generation that maintains compliance.