Weakness reference
CWE-78

OS Command Injection

OS Command Injection occurs when an application passes unsanitized user input directly to a system shell or command interpreter. An attacker can inject shell…

01Summary

OS Command Injection occurs when an application passes unsanitized user input directly to a system shell or command interpreter. An attacker can inject shell metacharacters (like |, ;, &, or backticks) to execute arbitrary commands on the server with the privileges of the web application. This is one of the most dangerous input validation flaws because it grants direct access to the operating system.

02How It Happens

Applications sometimes need to invoke system commands—to resize images, compress files, ping a host, or interact with external tools. When developers construct these commands by concatenating user input directly into a command string, they create an injection point. The shell interprets special characters in the input as command separators or operators rather than literal data. For example, a semicolon ends one command and starts another; a pipe chains commands together. If input validation is missing or incomplete, an attacker can break out of the intended command and execute anything the application's process can run.

03Real-World Impact

Successful OS command injection gives an attacker shell-level access to the server. They can read sensitive files, modify or delete data, install malware, pivot to other systems on the network, or take the application offline entirely. The impact is typically severe because the attacker operates with the same privileges as the web application process—often a dedicated user account, but sometimes root or a highly privileged service account. Even a seemingly minor command execution can become a foothold for further compromise.

04Vulnerable & Fixed Patterns

Vulnerable pattern
import subprocess
import sys

def resize_image(filename, width):
    # User input is directly interpolated into the command
    command = f"convert {filename} -resize {width}x{width} output.jpg"
    result = subprocess.run(command, shell=True, capture_output=True)
    return result.stdout

Why it's vulnerable:
The shell=True parameter causes the string to be interpreted by a shell. If filename or width contains shell metacharacters (e.g., image.jpg; rm -rf /), the attacker's injected command will execute.

Fixed pattern
import subprocess

def resize_image(filename, width):
    # Pass arguments as a list; no shell interpretation
    command = ["convert", filename, "-resize", f"{width}x{width}", "output.jpg"]
    result = subprocess.run(command, shell=False, capture_output=True)
    return result.stdout
Vulnerable pattern
<?php
function ping_host($hostname) {
    // User input concatenated directly into command
    $output = shell_exec("ping -c 4 " . $_GET['host']);
    echo $output;
}
?>

Why it's vulnerable:
The $_GET['host'] parameter is directly embedded in the shell command. An attacker can inject ; cat /etc/passwd or similar to execute additional commands.

Fixed pattern
<?php
function ping_host($hostname) {
    // Validate input against a strict allowlist
    if (!preg_match('/^[a-zA-Z0-9.-]+$/', $hostname)) {
        die("Invalid hostname");
    }
    // Use escapeshellarg() as a secondary defense
    $safe_host = escapeshellarg($hostname);
    $output = shell_exec("ping -c 4 " . $safe_host);
    echo $output;
}
?>

05Prevention Checklist

Avoid shell execution entirely.
Use language-native libraries or APIs instead of invoking system commands. For example, use image processing libraries rather than shelling out to convert.
Never use shell=True (Python) or shell_exec() (PHP) with user input.
If you must invoke a command, pass arguments as an array/list to prevent shell interpretation.
Validate and allowlist input.
Accept only expected formats (e.g., alphanumeric hostnames, numeric port numbers). Reject anything that doesn't match.
Use escapeshellarg() (PHP) or equivalent as a secondary defense,
not a primary one. It quotes arguments but is not foolproof if combined with shell=True.
Run the application with minimal privileges.
Use a dedicated, unprivileged system user account so that even if injection succeeds, the attacker's access is limited.
Log and monitor command execution.
Track which commands are being run and by whom; unusual patterns may indicate an attack in progress.

06Signs You May Already Be Affected

Check your application logs for unexpected system commands, unusual process spawning, or error messages from shell interpreters. Look for suspicious characters in request parameters (;, |, &, backticks, $()) in access logs. If you find unfamiliar files in your web root or system directories, or if system resource usage spikes unexpectedly, investigate whether command injection has been exploited.

07Related Recent Vulnerabilities