100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Security

Command Injection

Understand how command injection lets attackers execute arbitrary operating system commands through vulnerable application inputs, and why it's often more dangerous than SQL Injection.

Injection & InputIntermediate8 min readJul 10, 2026
Analogies

What Is Command Injection?

Command injection occurs when an application passes untrusted input to a system shell or OS command execution function — such as exec(), system(), subprocess.run(shell=True), or Node's child_process.exec() — without properly separating the command from its arguments. Because shells interpret special characters like ;, &&, |, and backticks as command separators or substitution operators, an attacker can append entirely new commands to whatever the application intended to run, executing them with the same privileges as the vulnerable application process.

🏏

Cricket analogy: It is like a groundskeeper who takes a written request 'water the pitch' and reads it aloud to a machine that also understands punctuation as new instructions, so a request ending in '; also unlock the equipment shed' gets carried out too.

Exploitation Techniques

A common real-world example is a network diagnostic tool on a router's web interface that lets a user 'ping' a hostname; if the backend runs system("ping -c 4 " + userInput), an attacker submitting 8.8.8.8; cat /etc/passwd causes the shell to run the ping command and then separately dump the password file. Attackers also use command substitution syntax like backticks or $() to embed a command's output directly into another command's arguments, and blind command injection (where no output is returned) can be exploited using out-of-band techniques such as triggering a DNS lookup or an outbound curl request to an attacker-controlled server to confirm execution.

🏏

Cricket analogy: It is like submitting a request to 'check the pitch moisture; also, hand me the ground curator's master key' — the system executes both parts because it never validated that only a moisture reading was requested.

python
# VULNERABLE: user input passed directly to a shell
import subprocess

def ping_host(hostname):
    # attacker sends: 8.8.8.8; cat /etc/passwd
    result = subprocess.run(f"ping -c 4 {hostname}", shell=True, capture_output=True)
    return result.stdout

# SAFE: arguments passed as a list, no shell interpretation of separators
import subprocess
import shlex

def ping_host_safe(hostname):
    # still validate hostname format before use, e.g. against a strict regex
    result = subprocess.run(["ping", "-c", "4", hostname], shell=False, capture_output=True)
    return result.stdout

Command Injection vs SQL Injection

Both vulnerabilities share the same root cause — untrusted input mixed with a command interpreter's syntax — but command injection is often more severe because it grants direct access to the underlying operating system rather than just the database. A successful command injection can read arbitrary files, install malware, establish a reverse shell for persistent remote access, or pivot to other systems on the network, whereas SQL Injection is typically constrained to whatever the database engine and its configured permissions allow.

🏏

Cricket analogy: SQLi is like breaching the scorer's table and altering the scorebook, while command injection is like walking straight into the groundskeeper's shed and taking control of the entire stadium's infrastructure.

Detecting and Mitigating

The most reliable fix is to avoid shell invocation entirely: use library APIs (e.g. a DNS resolution library instead of shelling out to ping) or, when a subprocess is genuinely necessary, call the executable with an argument array (shell=False / execve-style invocation) rather than a single interpolated string, so shell metacharacters are never interpreted. When shell use is unavoidable, strictly allow-list expected input (e.g. validate a hostname against a regex that only permits alphanumeric characters, dots, and hyphens) rather than trying to blocklist dangerous characters, since blocklists are notoriously easy to bypass with encoding tricks or unexpected shell features.

🏏

Cricket analogy: It is like replacing a verbal request to the curator with a fixed dropdown menu of pre-approved pitch treatments, so no one can ever type in an arbitrary instruction disguised as a request.

Never try to sanitize dangerous input by stripping or escaping specific characters like ; or | as your only defense — attackers routinely bypass blocklists using alternate encodings, newline characters, or shell features you didn't anticipate. Prefer argument-array execution or allow-listing instead.

  • Command injection happens when untrusted input reaches a shell or OS command execution function.
  • Shell metacharacters like ;, &&, |, and backticks let attackers append or substitute commands.
  • Blind command injection can be confirmed using out-of-band DNS or HTTP callbacks.
  • Command injection often grants OS-level access, making it typically more severe than SQL Injection.
  • The best fix is avoiding shell invocation entirely or using argument-array execution (shell=False).
  • Allow-listing valid input is far more reliable than blocklisting dangerous characters.
  • Successful exploitation can lead to reverse shells, malware installation, and lateral network movement.

Practice what you learned

Was this page helpful?

Topics covered

#Security#WebSecurityOWASPStudyNotes#CyberSecurity#CommandInjection#Command#Injection#Exploitation#Techniques#StudyNotes#SkillVeris