Introduction :
According to the OWASP Top 10 Web Application Security Risks rankings, injection vulnerabilities such as SQL injection and OS command injection have consistently been among the most common and dangerous risks to web applications. With that in mind, developers and security practitioners need to know these vulnerabilities and how to prevent them.
In this article, we will talk specifically about OS command injection: what it is, the different types , examples of OS command injection and best practices to defend against this type of injection.
What is OS command injection ?
OS command injection, also known as shell injection, is a vulnerability that allows an attacker to execute commands on the host operating system through a vulnerable application. But before we understand shell injection, we should first know what a shell is ?
A shell is a program that accepts text commands and runs them on the computer (e.g.,bash/sh on Linux and macOS,cmd.exe or PowerShell on Windows). When an application passes a string to the shell, the shell interprets and executes those commands.
OS command injection happens when unsafe user-supplied data (from forms, cookies, HTTP headers, etc.) is passed to the operating system without proper validation. In simple terms, it occurs when server-side code (such as PHP, Java, or Python) calls functions that interact directly with the system’s shell.

Now let’s dive deeper
Let’s examine the example below to better understand how a shell injection vulnerability can occur from a backend code perspective :
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
public void runUnsafe(HttpServletRequest request) throws IOException {
String cmd = request.getParameter("command");
String arg = request.getParameter("arg");
Runtime.getRuntime().exec(cmd + " " + arg);
}
As explained earlier, two main conditions must be present for command injection to take place:
- First, the application must call a function that directly interacts with the operating system.
- Second, the parameters passed into this function must be user-controlled, meaning they originate from client-side input such as query parameters, form fields, or headers.
Going back to our example, we can see that line 7 fulfills the first condition through the use of the Runtime.exec() function, which executes commands on the underlying operating system. The second condition is satisfied because the variables cmd and arg, defined in lines 5 and 6, are populated directly from the HTTP request parameters. In other words, whatever the client sends is passed straight into the operating system command without any validation.
For example, if an attacker enters cat as the command and /etc/passwd as the argument, they can exfiltrate data from the system.
let’s take another example :
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
public void runPing(HttpServletRequest request) throws IOException {
String host = request.getParameter("host");
Runtime.getRuntime().exec("ping " + host);
}
Exploiting this code with the input 127.0.0.1 && whoami produces an output such as:
PING 127.0.0.1 (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.043 ms
--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss
current_username
The successful execution of whoami demonstrates a lack of input sanitization: because untrusted input is passed directly to the shell, an attacker can append shell operators (;, &&, ||) to run additional commands. In this case the response reveals the system username which can be sensitive information and should not be exposed to ordinary users.
Types of OS command injection:
-
In-band command injection : the attacker executes commands in the host operating system and gets the result directly in the application’s response.
-
Blind command injection: The injected command still runs, but its output does not appear in the HTTP response. To exploit this, the attacker must rely on indirect techniques such as timing delays to observe the effects.
Impact of OS command injection:
Command injection attack can be severe and affect the CIA triad largely , depending on the application’s access rights , for example attacker can :
-
Gather system information such as the current user, directory structure, or environment variables.
-
Exfiltrate data by reading sensitive files like
/etc/passwd. -
Gain remote control through a reverse shell, effectively taking over the server.
-
Establish persistence by installing backdoors, creating malicious cron jobs, or leaving other hidden access points.
How to prevent command injection :
- Instead of directly executing operating system (OS) commands, use safer platform APIs to prevent command injection. In Java,
java.lang.ProcessBuilderis a more secure option than the outdatedRuntime.exec().
How to use ProcessBuilder ?
ProcessBuilder constructs a command using a list of strings (the program and its arguments), which helps avoid dangerous shell parsing. This approach treats each part of the command as a separate, safe argument rather than a single string that could be manipulated.
A Safer, but Not Total Solution !
While ProcessBuilder with argument arrays significantly mitigates shell parsing risks, it is a safer API choice, not a complete solution. You must still :
- Strictly validate input : and use whitelists for expected input like numbers , domains or IP addresses.
- Use the principles of sandboxing and least privilege by running processes with restricted access rights, ensuring that even if an injection occurs, the potential damage is limited.
That’s all for this article. If you have any questions, feel free to reach out to me on LinkedIn or X(Twitter) :
RESOURCES :
-Command Injection | Complete Guide
-OWASP official documentation for Command injection
-Portswigger course
-java official documentation