How to Use escapeshellarg in PHP for Safe CLI Execution
Running system commands from a PHP script can introduce severe
security risks if user input is not properly sanitized. This article
explains how to use PHP’s native escapeshellarg() function
to safely escape command-line arguments, preventing command injection
vulnerabilities and ensuring secure shell execution.
Understanding escapeshellarg()
When executing shell commands via PHP functions like
exec(), shell_exec(), system(),
or passthru(), passing raw user input directly to the shell
is dangerous. An attacker can append malicious commands using shell
operators such as ;, &&, or
|.
The escapeshellarg() function solves this by wrapping
the input string in single quotes and escaping any existing single
quotes within the string. This forces the shell to treat the entire
string as a single, literal argument rather than executable command
syntax.
Practical Code Example
The following examples demonstrate the difference between unsafe
command execution and safe command execution using
escapeshellarg().
The Unsafe Way (Vulnerable to Command Injection)
If user input is concatenated directly into the command string, malicious commands can be executed:
// User input containing a malicious command payload
$userInput = "image.jpg; rm -rf /";
// The shell will execute: convert image.jpg; rm -rf / output.png
$output = shell_exec("convert " . $userInput . " output.png");The Safe Way (Using escapeshellarg)
By passing the user input through escapeshellarg(), the
malicious payload is neutralized:
// User input containing a malicious command payload
$userInput = "image.jpg; rm -rf /";
// Escape the argument safely
$safeInput = escapeshellarg($userInput);
// The shell will execute: convert 'image.jpg; rm -rf /' output.png
$output = shell_exec("convert " . $safeInput . " output.png");In the safe example, escapeshellarg() converts the input
into 'image.jpg; rm -rf /'. The system treats this entire
string as a single filename argument, preventing the rm -rf
command from running.
Key Considerations
- OS-Specific Behavior:
escapeshellarg()automatically adapts to the hosting operating system. On Linux/Unix, it wraps arguments in single quotes. On Windows, it replaces double quotes with spaces, escapes percent signs, and encloses the argument in double quotes. - Arguments vs. Commands: Use
escapeshellarg()for individual arguments passed to a command. Do not use it for the command itself. If you must escape a whole command string, useescapeshellcmd(), though escaping individual arguments withescapeshellarg()is the standard best practice for robust security.