skills/command-injection-anti-pattern/SKILL.md
Security anti-pattern for OS Command Injection vulnerabilities (CWE-78). Use when generating or reviewing code that executes shell commands, runs system processes, or handles user input in command-line operations. Detects shell string concatenation and recommends argument arrays.
npx skillsauth add igbuend/grimbard command-injection-anti-patternInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Severity: Critical
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.
User input embedded in shell command strings enables command injection. The shell cannot distinguish between intended commands and attacker-injected commands.
# 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.
# 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}")
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);
});
}
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();
}
}
Python:
os.system() with any user inputsubprocess.run() or subprocess.Popen() with shell=True"command " + user_inputf"command {user_input}"JavaScript/Node.js:
child_process.exec() with user input`command ${userInput}`"command " + userInputJava:
Runtime.getRuntime().exec() with string concatenationexec() instead of string arrayPHP:
exec(), system(), shell_exec(), passthru() with user input"command " . $userInputSearch Patterns:
shell=True|exec\(|system\(|child_process\.execsubprocess.run(["command", "arg1", "arg2"], shell=False)).shell=True with user-controlled input to execution functions.Manual Testing:
;, |, &, $(), `, &&, ||; ls, | whoami, & cat /etc/passwd, `id`Automated Testing:
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
development
Security anti-pattern for Cross-Site Scripting vulnerabilities (CWE-79). Use when generating or reviewing code that renders HTML, handles user input in web pages, uses innerHTML/document.write, or builds dynamic web content. Covers Reflected, Stored, and DOM-based XSS. AI code has 86% XSS failure rate.
development
Security anti-pattern for XPath injection vulnerabilities (CWE-643). Use when generating or reviewing code that queries XML documents, constructs XPath expressions, or handles user input in XML operations. Detects unescaped quotes and special characters in XPath queries.
development
Security anti-pattern for weak password hashing (CWE-327, CWE-759). Use when generating or reviewing code that stores or verifies user passwords. Detects use of MD5, SHA1, SHA256 without salt, or missing password hashing entirely. Recommends bcrypt, Argon2, or scrypt.
development
Security anti-pattern for weak encryption (CWE-326, CWE-327). Use when generating or reviewing code that encrypts data, handles encryption keys, or uses cryptographic modes. Detects DES, ECB mode, static IVs, and custom crypto implementations.