Skip to main content

Overview

Code Injection occurs when an application incorporates untrusted data into dynamically evaluated or executed code. This allows an attacker to inject malicious code (e.g., PHP, Python, JavaScript, shell commands depending on the context) that gets executed by the server or, in some cases, the client. Common sinks include functions like eval(), template engines processing user input unsafely, and unsafe deserialization. 💻💥

Business Impact

Successful Code Injection often leads to Remote Code Execution (RCE), giving the attacker full control over the server hosting the application. They can steal data, install malware, deface the website, use the server for further attacks, or completely destroy the system. It is one of the most critical web vulnerabilities.

Reference Details

CWE ID: CWE-94 OWASP Top 10 (2021): A03:2021 - Injection Severity: Critical

Framework-Specific Analysis and Remediation

This vulnerability usually stems from the misuse of powerful, dynamic language features or libraries. The core principle for prevention is to never pass untrusted user input directly into functions that execute code or interpret strings as code. Use safer alternatives, structured data formats (like JSON), and always validate/sanitize input.
  • Python
  • Java
  • .NET(C#)
  • PHP
  • Node.js
  • Ruby

Framework Context

Using functions like eval(), exec(), or unsafe use of pickle for deserialization. Server-Side Template Injection (SSTI) in engines like Jinja2 if user input isn’t properly handled.

Vulnerable Scenario 1: Using eval() with User Input

An endpoint takes a mathematical expression from the user and evaluates it.
# calculator/views.py
from django.http import HttpResponse

def calculate(request):
    expression = request.GET.get('expr')
    if expression:
        try:
            # DANGEROUS: eval() executes any Python code.
            # Attacker input: '__import__("os").system("rm -rf /")'
            result = eval(expression, {"__builtins__": {}}) # Limiting builtins is not enough!
            return HttpResponse(f"Result: {result}")
        except Exception as e:
            return HttpResponse(f"Error: {e}", status=400)
    return HttpResponse("Enter expression via ?expr=")

Vulnerable Scenario 2: Unsafe Deserialization with pickle

Loading user session data or preferences stored using pickle.
# session_handler.py
import pickle
import base64

def load_user_prefs(request):
    prefs_cookie = request.COOKIES.get('user_prefs_pickle')
    if prefs_cookie:
        try:
            # DANGEROUS: pickle.loads() can execute arbitrary code
            # embedded in the pickled data by an attacker.
            prefs_data = base64.b64decode(prefs_cookie)
            prefs = pickle.loads(prefs_data)
            return prefs
        except Exception as e:
            print(f"Error loading prefs: {e}")
    return {}

Mitigation and Best Practices

Never use eval() or exec() with untrusted input. Use safe parsers (like ast.literal_eval for simple literals or specific math parsers). Never use pickle with untrusted data. Use safe serialization formats like JSON. For templates, ensure user input is always properly escaped and not used in template logic directly.

Secure Code Example

# calculator/views.py (Secure - using a safe math parser)
# Assume 'safe_math_eval' is a function using a library like 'numexpr'
# or a carefully crafted parser using 'ast'.
def calculate_safe(request):
    expression = request.GET.get('expr')
    if expression:
        try:
            # SECURE: Using a dedicated, safe evaluation method.
            result = safe_math_eval(expression)
            return HttpResponse(f"Result: {result}")
        except Exception as e: # Catch specific parsing errors
            return HttpResponse(f"Invalid expression: {e}", status=400)
    # ...

# session_handler.py (Secure - using JSON)
import json
import base64

def load_user_prefs_secure(request):
    prefs_cookie = request.COOKIES.get('user_prefs_json')
    if prefs_cookie:
        try:
            # SECURE: json.loads() only parses data, doesn't execute code.
            prefs_data = base64.b64decode(prefs_cookie)
            prefs = json.loads(prefs_data)
            return prefs
        except (json.JSONDecodeError, ValueError, TypeError) as e:
            print(f"Error loading prefs: {e}")
    return {}

Testing Strategy

Scan code for eval(), exec(), pickle.loads(). Review template code for places where user input might be interpreted as template directives (SSTI). Test endpoints by providing input designed to execute OS commands or reveal internal state (e.g., {{ 7*7 }} in templates, __import__('os').system('ls') for eval).