Pentesting
command injection
OS command injection
OWASP

Command Injection: OS Attacks, Impact & Prevention

What OS command injection is: how the attack works, shell metacharacters, blind and time-based variants, business impact and prevention.

SecraJuly 6, 20269 min read

OS command injection, often shortened to command injection, is a vulnerability that lets an attacker run arbitrary operating system commands on the server that hosts an application. It happens when code builds a call to the system shell by concatenating unchecked user input, so that data which should be treated as text ends up being interpreted as instructions. The outcome is usually direct and devastating: remote code execution (RCE) with the privileges of the vulnerable process and, in many cases, a full server takeover.

The essentials: command injection appears when an application passes untrusted input to a shell interpreter (/bin/sh, cmd.exe, PowerShell). Shell metacharacters let the attacker append their own commands to a legitimate one. The correct defense is not to escape characters, but to avoid the shell entirely and use APIs that receive arguments as a list, combined with allowlist validation and least privilege.

What OS command injection is

Many applications need to invoke system utilities: run a ping to check connectivity, convert an image with ImageMagick, compress a file or perform a DNS lookup. The problem arises when the developer delegates that task to the system shell and assembles the command by mixing a fixed template with data that comes from the user. The shell does not distinguish between what the programmer meant and what the attacker supplies: it interprets the whole string as a command line.

This class of flaw is catalogued as CWE-78 (Improper Neutralization of Special Elements used in an OS Command) and belongs to the A03:2021 Injection category of the OWASP Top 10, the same family as SQL injection. It should not be confused with code injection (where the attacker injects code in the application's own language, for example through eval): in command injection the target is the operating system's command interpreter, not the application runtime.

How the attack works: shell metacharacters

The heart of the attack is the metacharacter, a symbol the shell interprets with a special meaning instead of treating it as literal text. The most useful ones for an attacker are:

  • ; runs one command after another unconditionally.
  • | pipes the output of one command into another.
  • && and || run the second command depending on the success or failure of the first.
  • ` and $( ) command substitution: they run what is inside and place the output on the line.
  • & launches the command in the background.
  • A newline, which separates instructions just like in a script.

Vulnerable code versus safe code

Consider a classic feature: a panel that runs ping against an address supplied by the user. In Python, the insecure version invokes the shell by concatenating the input:

# VULNERABLE: input is interpreted by the shell
import os
ip = request.form["host"]
os.system("ping -c 1 " + ip)

If the attacker sends 127.0.0.1; cat /etc/passwd as the host value, the shell first runs the ping and then their command. With 127.0.0.1 && id or $(whoami) they extract system information. From there, downloading a reverse shell or a post-exploitation binary is trivial.

The safe version does not use the shell and passes the arguments as a list, so user input is never interpreted as syntax:

# SAFE: no shell, arguments as a list, with prior validation
import subprocess, ipaddress
ip = ipaddress.ip_address(request.form["host"])  # raises an exception if not a valid IP
subprocess.run(["ping", "-c", "1", str(ip)], shell=False, timeout=5)

In Node.js the same pattern means avoiding child_process.exec (which spawns a shell) and using execFile or spawn with the arguments passed separately. In Java, the key is ProcessBuilder with a list of arguments and no /bin/sh -c string. The general rule is simple: never let user input reach a shell interpreter.

Variants: blind and time-based injection

The application does not always return the command output in the response. When there is no visible echo we speak of blind command injection, and the attacker turns to indirect channels to confirm execution.

  • Time-based: it injects a controlled delay, for example ; sleep 10 on Linux or & timeout 10 on Windows. If the response takes ten extra seconds, execution is confirmed. This is the same logic as time-based SQL injection.
  • Out-of-band (OAST): it forces the server to generate outbound traffic toward a controlled domain, with nslookup attacker.oast.example, curl or ping. The DNS or HTTP request reaching the collaborator server proves execution even without any change in the response. Tools such as Burp Collaborator or interactsh automate this technique, and this out-of-band exfiltration logic is the same one abused in an SSRF attack, another vulnerability in the injection family.
  • Redirect to a readable file: writing the output to the web root with > /var/www/html/out.txt and reading it afterwards over HTTP.

To automate detection and exploitation there is commix, an open source tool specialised in command injection that systematically tries metacharacters, blind and time-based techniques. In a manual audit, Burp Suite remains the pivot for intercepting and modifying suspicious parameters.

Real business impact: from execution to server takeover

Command injection is not a low-profile vulnerability. By achieving code execution with the privileges of the web service, an attacker can read configuration files containing credentials, move laterally across the internal network, encrypt data or deploy a persistent implant. If the process runs as root or as a user with broad privileges, the server compromise is total.

Recent examples illustrate the severity. CVE-2024-3400 in Palo Alto Networks PAN-OS was an unauthenticated command injection in the GlobalProtect component, rated CVSS 10.0 and actively exploited in the Operation MidnightEclipse campaign. CVE-2024-21887 in Ivanti Connect Secure allowed command injection and, chained with an authentication bypass, led to mass compromises of corporate VPNs. And the historic CVE-2014-6271 (Shellshock) showed how a Bash weakness in processing environment variables opened RCE on thousands of servers. These cases are not theoretical: they are incidents that forced emergency patching at a global scale.

How to prevent command injection

Effective prevention relies on several layers that reinforce each other, following the defense-in-depth principle.

Avoid the shell and use parameterized APIs

The single most important measure is not to invoke the system shell. Whenever possible, solve the task with the language's native library: to read a file do not spawn cat, to resolve a DNS name use the resolver API, to manipulate images use a library binding. When running an external program is unavoidable, use APIs that receive the executable and its arguments as separate elements of an array (execFile, subprocess.run with shell=False, ProcessBuilder), so that input is never interpreted as shell syntax.

Allowlist input validation

Validate every input against an allowlist of expected values or formats and reject the rest. If a field must be an IP address, verify it with a strict parser; if it must be an identifier, apply an anchored regular expression such as ^[a-zA-Z0-9_-]+$. Blocklisting metacharacters is fragile: there is always a forgotten encoding or separator. This strict input validation is a defense that cuts across the whole injection family, as we detail in the 5 most common web vulnerabilities.

Least privilege and defense in depth

Run the service as the least privileged user possible, inside a container with reduced capabilities, seccomp and a read-only file system where appropriate. That way, even if the attacker manages to run a command, the blast radius stays contained. Complement this with egress filtering to detect OAST traffic and with monitoring of anomalous child processes spawned by the web service. This layered reasoning is the same one we apply against prompt injection in LLMs, where filtering keywords is not enough either.

Where it fits in OWASP and in an audit

Command injection is a priority target in any web application penetration test. The OWASP Web Security Testing Guide dedicates specific tests to command injection, and the Injection category leads the OWASP Top 10 year after year. The audit approach varies with the level of code access, an aspect we cover in our comparison of white box, black box and gray box testing: in white box you trace calls to system, exec or Runtime in the source code, while in black box you fuzz the parameters with metacharacters and blind payloads. If you need to verify your applications' exposure to this vector, our web and mobile audit service includes targeted command injection testing.

Frequently asked questions

What is the difference between command injection and SQL injection?

Both are injections and share the same root cause (mixing data and code), but the target differs. SQL injection abuses the database interpreter; command injection abuses the operating system's command interpreter. Command injection tends to have a more direct impact, because it leads to code execution on the server.

Is escaping special characters enough to stay protected?

Not as a primary defense. Escaping is error prone because each shell has different rules and some case is always left uncovered. The robust strategy is to avoid the shell and pass arguments as a list to a parameterized API, keeping allowlist validation as an additional layer.

What is blind command injection?

It is the variant in which the application does not return the command output in the response. The attacker confirms execution through indirect channels: introducing a delay with sleep (time-based) or forcing a DNS or HTTP request toward a server they control (out-of-band).

Can command injection happen on Windows?

Yes. The syntax changes (you use cmd.exe or PowerShell, and separators such as &, | or &&), but the flaw is identical: untrusted input reaching a command interpreter. Utilities such as timeout play the role of sleep for time-based tests.

Which tools help detect this vulnerability?

For manual testing, Burp Suite to intercept and modify parameters, complemented by OAST servers such as Burp Collaborator or interactsh for the blind variants. To automate, commix is specialised in command injection. In static analysis, SAST rules flag dangerous calls to system, exec or Runtime.

Command injection auditing with Secra

At Secra we treat command injection as a top-priority finding in our web application audits. We combine analysis of the code paths that invoke the shell, targeted parameter fuzzing with classic, blind and time-based payloads, and validation of real exploitability through controlled out-of-band techniques. We deliver findings prioritised by impact, with a reproducible proof of concept and concrete remediation guidance: removing the shell, adopting parameterized APIs, allowlist validation and privilege hardening. If you want to confirm that your applications do not expose this vector before an attacker discovers it, reach out through our contact page.

About the author

Secra Solutions team

Ethical hackers with OSCP, OSEP, OSWE, CRTO, CRTL and CARTE certifications, 7+ years of experience in offensive cybersecurity, and authors of CVE-2025-40652 and CVE-2023-3512.

Share article