CWE-15: External Control of System or Configuration Setting
Overview
This vulnerability occurs when user input is used to control system or application configuration settings, potentially allowing attackers to alter application behavior, security controls, or environment variables.
OWASP Classification
A02:2025 - Security Misconfiguration
Risk
High: If external input can influence system or security-sensitive configuration, attackers may weaken or disable security controls, alter trust boundaries, or redirect application behavior. This often acts as a bypass primitive that enables other vulnerabilities.
Remediation Steps
Core Principle: Never allow untrusted input to directly set configuration values; use an allowlist to constrain changes to known-safe values, require elevated authorization, and prefer immutable deployment-time configuration over runtime configuration changes.
Trace the Data Path
Analyze the data_path from source to sink to understand how untrusted data reaches the configuration sink:
- Source: Identify where untrusted data enters (HTTP parameters, request headers, POST body, cookies, query strings)
- Sink: Locate the configuration assignment (
config.set(),os.environ[key] = value,System.setProperty(), environment variable assignment) - Validation gaps: Check each frame between source and sink for missing allowlist validation or authorization checks
Eliminate Runtime Configuration Control (Preferred)
The safest approach is to remove the ability for users to modify configuration at runtime entirely:
- Set all configuration at application startup via environment variables, config files, or secret managers
- Never expose configuration-setting endpoints to end users
- Treat configuration as immutable once the application starts
- Use deployment-time mechanisms (CI/CD pipelines, infrastructure-as-code) to manage configuration changes
Restrict with an Allowlist (If Runtime Config Is Required)
If runtime configuration changes are a genuine product requirement, constrain them strictly:
- Define an explicit allowlist of permitted values for each configuration key
- Reject any value not on the allowlist — do not attempt sanitization
- Never accept arbitrary key names from user input; map user choices to internal keys
- Validate type and range for numeric settings (e.g., timeouts must be between 1–60 seconds)
- Restrict which settings users can change — security-critical settings must never be user-modifiable
Require Authorization for All Configuration Changes
Any configuration-changing endpoint must enforce strict access control:
- Require authentication — unauthenticated users must never reach config endpoints
- Require admin-level authorization — standard user roles must not be able to change configuration
- Audit all changes — log who changed what, to what value, and when
- Alert on anomalies — unexpected configuration change attempts should trigger alerts
Apply Least Privilege and Secure Defaults
Limit the blast radius if exploitation occurs:
- Secure defaults: All configuration fields should default to their most restrictive safe value
- Fail securely: If a change fails validation, revert to the previous secure value
- Isolate configuration surfaces: Admin interfaces should only be reachable from internal networks
Test Configuration Manipulation Attempts
Verify the fix prevents malicious configuration changes:
- Test with values outside the allowlist — invalid values should be rejected with no change applied
- Test with shell metacharacters and path traversal —
../../etc/passwd,; rm -rf /should fail - Test without authorization — configuration endpoints should return 401/403 without valid admin credentials
- Test boundary values — for numeric configs, verify minimum and maximum bounds are enforced
Untrusted Configuration Sources
A related but distinct attack vector occurs when the application reads configuration from a location that untrusted input controls, rather than assigning individual values directly.
Common Untrusted Source Patterns
- User-supplied file path passed to a config file parser (
configparser.read(path),new FileInputStream(path)) - User-supplied URL fetched and parsed as configuration (fetching remote JSON/YAML configs)
- User-uploaded file (JSON, YAML, XML,
.properties) applied directly as application configuration - Database rows that users can write to, later read back and applied as config without re-validation
Risks
- Path traversal: A user-controlled path like
../../etc/passwdis read and parsed as configuration, potentially exposing internal file contents or overriding settings with arbitrary file data - SSRF: A user-controlled config URL can be pointed at internal services (AWS metadata endpoint
169.254.169.254, internal APIs, database admin interfaces) — see also CWE-918 - Unsafe deserialization: Attacker-controlled YAML/XML can trigger code execution during parsing if unsafe parsers are used — see also CWE-502 and CWE-611
- Second-order injection: Config stored in a database by one user and later applied globally affects all users
Remediation
- Never load config files from user-supplied paths — file paths used for config must be hardcoded or derived from a trusted allowlist of directories, never from request parameters
- Never fetch configuration from user-supplied URLs — use only hardcoded internal config service endpoints; if a URL must be configurable, it must be an admin-only setting validated against a strict domain allowlist
- Use safe parsers for uploaded config — use
yaml.safe_load()notyaml.load(), disable external entity processing in XML parsers, and schema-validate content before applying any values - Treat database-sourced config as untrusted — apply the same allowlist and type validation as HTTP input before acting on config values read from storage
Language-Specific Guidance
For detailed, framework-specific code examples and patterns, see:
- C# - ASP.NET Core
IOptions<T>validation,LoggingLevelSwitch, safe config file loading - Java - Spring Boot
@ConfigurationProperties, JSR-303 validation,@PreAuthorize, safe path loading - JavaScript - Node.js
process.envimmutability, dotenv, zod allowlist validation, safe URL loading - Python - Pydantic
BaseSettings, Django/Flask config class patterns,yaml.safe_load()
Validate environment variables with type checking
private static readonly HashSet<string> ALLOWED_CONFIG_KEYS = new HashSet<string>
{
"FEATURE_FLAG_A",
"CACHE_TTL",
"MAX_UPLOAD_SIZE"
};
[HttpPost("config/env")]
[Authorize(Roles = "Admin")]
public IActionResult SetEnvironment([FromBody] ConfigRequest req)
{
if (!ALLOWED_CONFIG_KEYS.Contains(req.Key))
{
return BadRequest("Configuration key not allowed");
}
// Validate value based on key
if (req.Key == "CACHE_TTL" && !int.TryParse(req.Value, out int ttl))
{
return BadRequest("CACHE_TTL must be an integer");
}
if (req.Key == "FEATURE_FLAG_A" && !bool.TryParse(req.Value, out _))
{
return BadRequest("FEATURE_FLAG_A must be true or false");
}
Environment.SetEnvironmentVariable(req.Key, req.Value);
_auditLogger.Log($"Config {req.Key} set to {req.Value} by {User.Identity.Name}");
return Ok("Environment updated");
}
Why this works: Validates configuration key against allowlist of permitted keys, preventing arbitrary environment variable manipulation. Performs type checking for each configuration value based on expected type. Requires admin authorization and logs all changes.
Enforce range limits on numeric configuration values
@app.route('/config/timeout')
@require_admin_role
def set_timeout():
try:
timeout = int(request.args.get('timeout', 30))
except ValueError:
return "Invalid timeout value", 400
# Enforce reasonable range
MIN_TIMEOUT = 5
MAX_TIMEOUT = 300
if timeout < MIN_TIMEOUT or timeout > MAX_TIMEOUT:
return f"Timeout must be between {MIN_TIMEOUT} and {MAX_TIMEOUT} seconds", 400
config['request_timeout'] = timeout
audit_log(f"Request timeout changed to {timeout}s by {current_user}")
return "Timeout updated"
Why this works: Validates timeout is a valid integer (catches ValueError on non-numeric input). Enforces minimum and maximum bounds to prevent DoS via extreme values (too low causes failures, too high causes resource exhaustion). Requires admin privileges and logs changes.