command-injection-anti-pattern
SKILL.md
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
# 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
# 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:
// 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:
// 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:
// 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:
// 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 inputsubprocess.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:
# 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
Weekly Installs
4
Repository
igbuend/grimbardGitHub Stars
4
First Seen
Jan 20, 2026
Security Audits
Installed on
claude-code4
codex4
cursor4
opencode4
trae-cn3
gemini-cli3