Weakness reference
CWE-96

Improper Neutralization of Directives in Statically Included Code ('Static Code Injection')

Static code injection occurs when user input is directly embedded into code that is then parsed and executed as part of the application's logic, without…

01Summary

Static code injection occurs when user input is directly embedded into code that is then parsed and executed as part of the application's logic, without sanitization or validation. Unlike dynamic code injection (eval), this weakness involves code that is written to disk or configuration files and then loaded as part of the normal application flow. An attacker can inject malicious code directives that alter the application's behavior or bypass security controls.

02How It Happens

This weakness arises when an application treats user-supplied data as trusted code during a build, initialization, or configuration phase. Common scenarios include:

- Writing user input directly into configuration files, template files, or include paths that are later parsed by the application. - Allowing users to specify which code modules or files to load without validation. - Embedding user input into code generation scripts or build-time templates. - Accepting user-controlled data in serialized objects or markup that define application behavior.

The key difference from dynamic injection is that the malicious code is "static" — it becomes part of the application's codebase or configuration before runtime, rather than being evaluated on-the-fly. This can make detection harder and impact more difficult to contain.

03Real-World Impact

Successful exploitation can lead to complete application compromise. An attacker may alter business logic, bypass authentication checks, exfiltrate sensitive data, or inject backdoors that persist across restarts. Because the injected code is part of the application's static configuration or codebase, it may survive security scans that only monitor runtime behavior. The impact is often severe and difficult to remediate without a full code audit and rebuild.

04Vulnerable & Fixed Patterns

Vulnerable pattern
# Configuration file is built from user input
user_module_name = request.args.get('module')
config_content = f"""
import sys
sys.path.insert(0, '/app/modules')
from {user_module_name} import handler
"""

with open('/app/config.py', 'w') as f:
    f.write(config_content)

# Later, the application loads and executes this config
exec(open('/app/config.py').read())

Why it's vulnerable:
The user-supplied module parameter is directly interpolated into Python code that is written to disk and then executed. An attacker could inject arbitrary import statements or code.

Fixed pattern
# Define an allowlist of safe modules
ALLOWED_MODULES = {'handler_a', 'handler_b', 'handler_c'}

user_module_name = request.args.get('module', 'handler_a')

# Validate against allowlist
if user_module_name not in ALLOWED_MODULES:
    raise ValueError(f"Module '{user_module_name}' is not permitted")

# Use safe import mechanism
config_content = f"""
import sys
sys.path.insert(0, '/app/modules')
from {user_module_name} import handler
"""

with open('/app/config.py', 'w') as f:
    f.write(config_content)
Vulnerable pattern
<?php
// User input is written directly into a PHP include file
$template_name = $_GET['template'];
$config_code = "<?php\n\$active_template = '{$template_name}';\n?>";

file_put_contents('/app/config.php', $config_code);

// Later, the application includes this file
include('/app/config.php');
?>

Why it's vulnerable:
The template parameter is directly embedded into PHP code written to disk. An attacker could inject PHP code that executes when the file is included.

Fixed pattern
<?php
// Define an allowlist of safe templates
$allowed_templates = array('default', 'minimal', 'premium');

$template_name = isset($_GET['template']) ? $_GET['template'] : 'default';

// Validate against allowlist
if (!in_array($template_name, $allowed_templates, true)) {
    $template_name = 'default';
}

// Use safe assignment without code generation
$config_code = "<?php\n\$active_template = " . var_export($template_name, true) . ";\n?>";

file_put_contents('/app/config.php', $config_code);

include('/app/config.php');
?>

05Prevention Checklist

Use allowlists, not blacklists.
Define a strict set of permitted values (module names, template names, configuration keys) and reject anything outside that set.
Never interpolate user input into code strings.
If you must generate code, use parameterized or templating mechanisms that separate data from logic.
Avoid writing user input to files that are later parsed as code.
Store configuration in data-only formats (JSON, YAML, INI) and parse them safely.
Validate and sanitize all input before any code generation or file write.
Use type checking, length limits, and character whitelisting.
Use dependency injection or configuration objects instead of dynamic imports.
Pre-define available modules and load them by reference, not by user-supplied name.
Review build and initialization scripts.
Ensure that no user-controlled data flows into code generation, template expansion, or module loading logic.

06Signs You May Already Be Affected

Look for unexpected files in configuration directories, unusual entries in version control history showing code changes that don't match your deployments, or application behavior that changes without code updates. Check logs for failed include/import attempts or syntax errors in configuration files. If you find PHP or Python code in configuration files that you did not write, or if your application loads modules based on user input, investigate immediately.

07Related Recent Vulnerabilities