CWE-114: Process Control
Overview
Process control vulnerabilities occur when applications accept untrusted input to control process execution, library loading, or behavior (start, stop, kill, priority, resource limits). This includes insecure dynamic library loading (DLL hijacking, LD_PRELOAD attacks), command injection through process execution, and unauthorized process control. Attackers exploit weak validation to load malicious libraries, execute arbitrary commands, or manipulate running processes.
OWASP Classification
A05:2025 - Injection
Relationship to Other CWEs
CWE-114 and CWE-78 address different aspects of process security:
CWE-114 (Process Control) - Untrusted data controls which process/library to execute:
- Focus: Controlling the executable path, library name, or process lifecycle (start/stop/kill)
- Examples:
System.loadLibrary(userInput),dlopen(userPath),LoadLibrary(userDll),os.kill(userPid) - Prevention: Absolute paths, allowlist validation, path traversal prevention, signature verification
- No shell involved: Direct API calls to load libraries or control processes
CWE-78 (OS Command Injection) - Untrusted data interpreted by shell as commands:
- Focus: Shell metacharacters in arguments (
;,|,&,$(), backticks) - Examples:
system("convert " + userInput),exec("grep " + userPattern) - Prevention: Avoid shell execution, use argument arrays, input sanitization
- Requires shell: Vulnerability exists because shell interprets special characters
Overlap scenarios (both apply):
Runtime.exec(userCommand)with shell - controls which program (CWE-114) and allows command injection (CWE-78)system(userInput)- controls which program and allows shell metacharacter injection
Distinct scenarios (CWE-114 only, no shell):
- Library loading:
System.load(),dlopen(),LoadLibrary()- no shell interpretation - Process lifecycle:
os.kill(),Process.kill()- no command execution - Direct execution:
execve(),ProcessBuilderwithout shell - prevents CWE-78 but still needs CWE-114 protection
Defense-in-depth: Secure patterns in this guidance prevent both vulnerabilities by:
- Using direct execution APIs without shell (prevents CWE-78)
- Validating executable paths and using allowlists (prevents CWE-114)
- Using argument arrays instead of string concatenation (prevents both)
Risk
High: Attackers can terminate critical processes, spawn malicious processes, exhaust system resources, or manipulate process priorities to cause denial of service or gain unauthorized control over system operations.
Remediation Steps
Core principle: Only load components from trusted, integrity-checked locations; control library/module search paths and provenance.
Identify the Process Control Vulnerability
Review the security findings to understand how untrusted data controls process operations:
- Locate the source: Find where untrusted data enters (HTTP parameters, database, external files, network requests)
- Trace to the sink: Identify the process control function (
os.kill(),Process.kill(),taskkill, etc.) - Understand the operation: Determine what process control action is being performed (kill, start, stop, priority change)
- Check the data flow: Review if there's any validation between source and sink
Implement Strict Authorization Checks
Add comprehensive access control before any process control operation:
- Authenticate the user: Verify the user's identity before allowing process control
- Implement RBAC: Use role-based access control - only admins/operators can control processes
- Require elevated privileges: For sensitive operations (system processes, critical services), require additional authentication
- Never trust untrusted data directly: Don't accept PIDs, process names, or control commands directly from untrusted sources
- Check process ownership: Verify the user owns the process before allowing control (or has admin role)
Use Allowlists for Process Operations
Restrict which processes can be controlled:
- Maintain allowlist of controllable processes: Define which processes/services can be managed via the application
- Validate against known-good values: Check process names or IDs against the allowlist before any operation
- Reject system/critical processes: Never allow control of system processes (init, systemd, kernel threads, Windows services)
- Use indirect references: Map user input to internal process IDs (e.g., user selects "job-123" which maps to a specific PID)
- Load allowlist from configuration: Store allowed processes in config files, not code
Validate All Process Control Parameters
Apply comprehensive validation to process identifiers and commands:
- Validate PIDs: Ensure process IDs are positive integers, within valid range
- Validate process names: Use allowlist, check for path traversal attempts
- Validate control commands: Only allow specific operations (start, stop, restart), reject arbitrary commands
- Check process existence: Verify the process exists before attempting control
- Verify process ownership: Ensure the process belongs to the application or authorized user
- Enforce resource limits: For process spawning, set memory, CPU, and time limits
Implement Logging and Monitoring
Detect and respond to suspicious process control activity:
- Log all operations: Record every process control attempt with user context, timestamp, operation type, target process
- Monitor for suspicious patterns: Alert on mass termination attempts, rapid process spawning, privilege escalation
- Alert on unauthorized attempts: Notify security team when authorization checks fail
- Audit process lifecycle: Track process creation, termination, and control events
- Implement rate limiting: Prevent automated abuse of process control endpoints
Test with Malicious Process Control Attempts
Verify the fix prevents unauthorized process control:
- Test with unauthorized user: Attempt process control as non-admin user (should be rejected)
- Test with invalid PIDs: Try negative numbers, zero, non-existent PIDs, extremely large PIDs
- Test with system processes: Attempt to kill system processes (should be blocked by allowlist)
- Test with SQL injection: If PID comes from database, test for SQL injection
- Test with mass operations: Attempt to kill multiple processes rapidly (should be rate-limited)
- Verify authorized users can control allowed processes: Ensure legitimate functionality works
Common Vulnerable Patterns
- Accepting user input for process kill/terminate operations
- Using user-controlled PIDs without validation
- Missing authorization checks on process control
- Allowing control of arbitrary system processes
- No rate limiting on process spawning
Language-Specific Guidance
For detailed, language-specific guidance with comprehensive code examples and security patterns:
- C: Secure native library loading with
dlopen()using absolute paths,LoadLibraryEx()on Windows,execve()for process execution, environment clearing, and LD_PRELOAD prevention - C#: Secure DLL loading with
DllImportandSetDllDirectory(),Process.Start()without shell execution, strong name verification for assemblies, and DLL hijacking prevention - Java: Secure library loading with
System.load()using absolute paths,ProcessBuilderfor command execution, path validation, allowlist enforcement, and SHA-256 verification - JavaScript/Node.js: Process control security in Node.js using
child_process, PM2, cluster module, and container orchestration - Python: Process control security using
os.kill(),subprocess,signalmodule, and frameworks like psutil, Celery, and Docker