Command Injection Anti-Pattern
Severity: Critical
Summary
Command injection allows attackers to execute arbitrary OS commands by manipulating user input. This anti-pattern occurs when applications concatenate user input into shell command strings. Common in AI-generated code. Enables complete system compromise, data exfiltration, malware installation, and lateral movement.
The Anti-Pattern
User input embedded in shell command strings enables command injection. The shell cannot distinguish between intended commands and attacker-injected commands.
BAD Code Example
python
# VULNERABLE: Shell command with user input
import os
def ping_host(hostname):
# User input is directly concatenated into the command string.
# An attacker can inject malicious commands separated by a semicolon or other shell metacharacters.
command = "ping -c 4 " + hostname
os.system(command)
# Example of a successful attack:
# hostname = "google.com; rm -rf /"
# Resulting command: "ping -c 4 google.com; rm -rf /"
# This executes the ping and then attempts to delete the entire filesystem.
GOOD Code Example
python
# SECURE: Use argument arrays, avoid shell
import subprocess
def ping_host(hostname):
# Validate input against allowlist
import re
if not re.match(r'^[a-zA-Z0-9.-]+$', hostname):
raise ValueError("Invalid hostname format")
# The command and its arguments are passed as a list.
# The underlying OS API executes the command directly without invoking a shell,
# so shell metacharacters in `hostname` are treated as a literal string.
try:
subprocess.run(["ping", "-c", "4", hostname], check=True, shell=False)
except subprocess.CalledProcessError as e:
print(f"Error executing ping: {e}")
JavaScript/Node.js Examples
BAD:
javascript
// VULNERABLE: Shell command with user input
const { exec } = require('child_process');
function pingHost(hostname) {
// User input concatenated into command string
exec(`ping -c 4 ${hostname}`, (error, stdout) => {
console.log(stdout);
});
}
// Attack: hostname = "google.com; cat /etc/passwd"
// Executes: ping -c 4 google.com; cat /etc/passwd
GOOD:
javascript
// SECURE: Use execFile with argument array
const { execFile } = require('child_process');
function pingHost(hostname) {
// Validate hostname format
if (!/^[a-zA-Z0-9.-]+$/.test(hostname)) {
throw new Error('Invalid hostname format');
}
// Arguments passed as array, no shell invocation
execFile('ping', ['-c', '4', hostname], (error, stdout) => {
if (error) {
console.error(`Error: ${error.message}`);
return;
}
console.log(stdout);
});
}
Java Examples
BAD:
java
// VULNERABLE: Runtime.exec() with string concatenation
public void pingHost(String hostname) {
try {
// String concatenation creates command injection risk
String command = "ping -c 4 " + hostname;
Runtime.getRuntime().exec(command);
} catch (IOException e) {
e.printStackTrace();
}
}
GOOD:
java
// SECURE: ProcessBuilder with argument array
import java.io.IOException;
import java.util.regex.Pattern;
public void pingHost(String hostname) {
// Validate hostname format
if (!Pattern.matches("^[a-zA-Z0-9.-]+$", hostname)) {
throw new IllegalArgumentException("Invalid hostname format");
}
try {
// Arguments in array, no shell interpretation
ProcessBuilder pb = new ProcessBuilder("ping", "-c", "4", hostname);
Process process = pb.start();
process.waitFor();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
Detection
Python:
- •
os.system()with any user input - •
subprocess.run()orsubprocess.Popen()withshell=True - •String concatenation:
"command " + user_input - •f-strings:
f"command {user_input}"
JavaScript/Node.js:
- •
child_process.exec()with user input - •Template literals:
`command ${userInput}` - •String concatenation:
"command " + userInput
Java:
- •
Runtime.getRuntime().exec()with string concatenation - •Single string argument to
exec()instead of string array
PHP:
- •
exec(),system(),shell_exec(),passthru()with user input - •String concatenation:
"command " . $userInput
Search Patterns:
- •Grep:
shell=True|exec\(|system\(|child_process\.exec - •Look for user input variables in command construction
- •Check for string concatenation or interpolation with command functions
Prevention
- • Use argument arrays instead of shell strings (e.g.,
subprocess.run(["command", "arg1", "arg2"], shell=False)). - • Never pass
shell=Truewith user-controlled input to execution functions. - • Validate all input against a strict allowlist of known-good values or formats.
- • Use language-specific libraries or APIs instead of external shell commands whenever possible.
- • Apply the Principle of Least Privilege to the process executing the command, restricting its permissions to the absolute minimum required.
Testing for Command Injection
Manual Testing:
- •Test shell metacharacters:
;,|,&,$(),`,&&,|| - •Input payloads:
; ls,| whoami,& cat /etc/passwd,`id` - •Verify commands execute safely without shell interpretation
- •Confirm metacharacters treated as literal strings
Automated Testing:
- •Static Analysis: Semgrep, Bandit (Python), ESLint security plugins, SpotBugs (Java)
- •DAST: Burp Suite, OWASP ZAP with command injection payloads
- •Code Review: Search for detection patterns above
Example Test:
python
# Test that shell metacharacters are treated literally
def test_command_injection_prevention():
malicious_input = "google.com; rm -rf /"
try:
ping_host(malicious_input) # Should fail validation
assert False, "Should reject malicious input"
except ValueError:
pass # Expected
Remediation Steps
- •Identify vulnerable code - Use detection patterns above
- •Validate necessity - Can you avoid shell commands entirely?
- •Replace with safe API - Use language-specific libraries when possible
- •Convert to argument arrays - Replace string concatenation
- •Remove shell=True - Never use with user input
- •Add input validation - Allowlist known-good patterns
- •Test the fix - Verify shell metacharacters are literal
- •Review similar code - Check for pattern across codebase
Related Security Patterns & Anti-Patterns
- •SQL Injection Anti-Pattern: A similar injection pattern targeting databases.
- •Path Traversal Anti-Pattern: Often combined with command injection to access or create files in unintended locations.
- •Missing Input Validation Anti-Pattern: A fundamental weakness that enables command injection.
References
- •OWASP Top 10 A05:2025 - Injection
- •OWASP GenAI LLM01:2025 - Prompt Injection
- •OWASP API Security API8:2023 - Security Misconfiguration
- •OWASP OS Command Injection Defense Cheat Sheet
- •CWE-78: OS Command Injection
- •CAPEC-88: OS Command Injection
- •PortSwigger: Os Command Injection
- •Source: sec-context