Weakness reference
CWE-913

Improper Control of Dynamically-Managed Code Resources

This weakness occurs when an application allows external input to influence how code is loaded, executed, or interpreted at runtime without proper validation…

01Summary

This weakness occurs when an application allows external input to influence how code is loaded, executed, or interpreted at runtime without proper validation or restrictions. Attackers can exploit this to inject malicious code, modify application behavior, or execute arbitrary logic by manipulating templates, class definitions, variable assignments, or other dynamic code resources. The risk is especially high in applications that use reflection, dynamic imports, template engines, or eval-like constructs.

02How It Happens

Many modern applications use dynamic code features for flexibility: template engines that render user-supplied content, reflection APIs that instantiate classes by name, or configuration systems that load code at runtime. When an application accepts external input (from URL parameters, uploaded files, database records, or API calls) and uses it directly to determine which code runs, load which class, or render which template without validation, an attacker can redirect execution to unintended code paths. The vulnerability is compounded when the application trusts user input to specify object properties, method names, or file paths that are then resolved dynamically.

03Real-World Impact

Successful exploitation can lead to arbitrary code execution, allowing an attacker to run any command the application has permission to execute. This may result in data theft, system compromise, installation of malware, or complete loss of confidentiality and integrity. Even if full code execution is not possible, attackers may be able to modify application state, bypass authentication, access sensitive files, or trigger unintended business logic.

04Vulnerable & Fixed Patterns

Vulnerable pattern
import importlib

# User input from request parameter
module_name = request.args.get('module')
class_name = request.args.get('class')

# Dynamically load and instantiate based on user input
module = importlib.import_module(module_name)
cls = getattr(module, class_name)
instance = cls()

Why it's vulnerable:
An attacker can specify any installed module and class name, potentially loading malicious or unintended code. There is no allowlist or validation of what may be loaded.

Fixed pattern
import importlib

# Define an allowlist of safe modules and classes
ALLOWED_CLASSES = {
    'handlers.user': ['UserHandler'],
    'handlers.admin': ['AdminHandler'],
}

module_name = request.args.get('module')
class_name = request.args.get('class')

# Validate against allowlist before loading
if module_name in ALLOWED_CLASSES and class_name in ALLOWED_CLASSES[module_name]:
    module = importlib.import_module(module_name)
    cls = getattr(module, class_name)
    instance = cls()
else:
    raise ValueError("Requested class not in allowlist")
Vulnerable pattern
<?php
// User input from GET parameter
$template_name = $_GET['template'];
$class_name = $_GET['class'];

// Dynamically load template and instantiate class
include("templates/{$template_name}.php");
$obj = new $class_name();
$obj->render();
?>

Why it's vulnerable:
An attacker can use path traversal (e.g., ../../../etc/passwd) to include arbitrary files, or specify any class name in scope to instantiate unintended objects with side effects.

Fixed pattern
<?php
// Define an allowlist of safe templates and classes
$allowed_templates = ['user_profile', 'dashboard', 'settings'];
$allowed_classes = ['UserRenderer', 'AdminRenderer'];

$template_name = $_GET['template'] ?? 'default';
$class_name = $_GET['class'] ?? 'DefaultRenderer';

// Validate against allowlist
if (in_array($template_name, $allowed_templates, true)) {
    include("templates/" . basename($template_name) . ".php");
}

if (in_array($class_name, $allowed_classes, true)) {
    $obj = new $class_name();
    $obj->render();
} else {
    throw new Exception("Class not allowed");
}
?>

05Prevention Checklist

Use allowlists, not blacklists.
Maintain an explicit list of safe modules, classes, templates, or functions that may be dynamically loaded; reject anything not on the list.
Avoid eval and dynamic code execution.
Never use eval(), exec(), or similar constructs with user input. If dynamic behavior is needed, use safer alternatives like configuration files or lookup tables.
Validate and sanitize input.
Even with allowlists, validate the type and format of user input before using it in dynamic operations.
Use basename() or similar path normalization.
If dynamic file inclusion is necessary, use basename() to strip directory components and prevent path traversal.
Restrict reflection and introspection.
Limit which classes, methods, and properties can be accessed via reflection APIs; use security managers or access control lists where available.
Review template engines and their settings.
Ensure template engines are configured to disable dangerous features (e.g., arbitrary function calls, file inclusion) and that user-supplied template content is sandboxed or pre-compiled.

06Signs You May Already Be Affected

Look for unexpected files in your application directories, unusual class instantiations in logs, or template files that were not created by your development team. Monitor for requests with suspicious module, class, template, or include parameters, and check for any unauthorized changes to configuration files or dynamically loaded code paths. If you use a template engine, audit recent template files for injected code or suspicious variable references.

07Related Recent Vulnerabilities