Learn how to securely execute shell scripts in PHP without security risks. Prevent command injection, restrict execution, and manage script permissions safely.
Introduction
Executing shell scripts from PHP enables powerful system automation, but improper execution can introduce critical security vulnerabilities such as command injection, privilege escalation, and unauthorized access.
With secure execution practices, you can:
- Prevent command injection by sanitizing input
- Restrict shell script execution to authorized commands
- Use proper file permissions to limit script access
- Log and monitor shell script execution
This guide covers:
- Understanding shell execution risks in PHP
- Securing PHP shell execution against injection attacks
- Restricting which scripts PHP can execute
- Managing script permissions and safe execution practices
1. Understanding Security Risks When Executing Shell Scripts in PHP
Common Security Risks
1. Command Injection – Attackers can execute arbitrary commands if input is not sanitized.
2. Privilege Escalation – Running scripts with excessive permissions can lead to unauthorized actions.
3. Unrestricted Script Execution – Allowing PHP to execute any shell command without restrictions can be dangerous.
4. Lack of Logging and Monitoring – Without logging, malicious activities may go unnoticed.
Unsafe Example (DO NOT USE)
$command = $_GET['cmd'];
shell_exec("bash $command"); // Dangerous! User can pass any command
An attacker could execute:
?cmd=; rm -rf /
This can wipe the entire server if the PHP script has enough privileges.
2. Preventing Command Injection in PHP Shell Execution
Use escapeshellarg() to Sanitize Input
$script = '/scripts/safe_script.sh';
$input = escapeshellarg($_GET['input']);
shell_exec("bash $script $input");
Why Use escapeshellarg()?
- Prevents command injection attacks
- Ensures input is treated as a single argument
3. Restricting Which Shell Scripts PHP Can Execute
Whitelist Approved Scripts for Execution
$allowedScripts = [
'backup' => '/scripts/backup.sh',
'cleanup' => '/scripts/cleanup.sh'
];
$script = $_GET['script'] ?? '';
if (isset($allowedScripts[$script])) {
shell_exec('bash ' . escapeshellarg($allowedScripts[$script]));
echo "Script executed.";
} else {
echo "Unauthorized script execution.";
}
Why Restrict Script Execution?
- Prevents arbitrary script execution
- Ensures only pre-approved scripts are run
4. Running Shell Scripts with Limited Permissions
Set Proper File Ownership and Permissions
To ensure scripts are only executable by the web server user:
chown www-data:www-data /scripts/safe_script.sh
chmod 750 /scripts/safe_script.sh
Why Use Limited Permissions?
- Prevents unauthorized users from modifying scripts
- Ensures PHP only executes scripts owned by the correct user
5. Using Sudo Securely in PHP Shell Execution
Grant Sudo Access to Specific Commands Only
If a script requires elevated privileges, do not allow full sudo access. Instead, specify allowed commands in sudoers
.
sudo visudo
Add the following line:
www-data ALL=(ALL) NOPASSWD: /scripts/backup.sh
Then execute in PHP:
$output = shell_exec('sudo bash /scripts/backup.sh');
echo "<pre>$output</pre>";
Why Use Limited Sudo Access?
- Prevents PHP from executing arbitrary sudo commands
- Ensures controlled privilege escalation
6. Logging and Monitoring Shell Script Execution
Log Every Execution Attempt
Modify scripts to log execution details.
Example: Logging Execution in a Shell Script
#!/bin/bash
echo "$(date) - Script executed by $(whoami) with args: $@" >> /var/log/script_execution.log
Checking Logs in PHP
echo nl2br(file_get_contents('/var/log/script_execution.log'));
Why Use Logging?
- Helps track unauthorized script execution
- Provides a history of executed commands
7. Running Shell Scripts in a Secure Environment
Use a Dedicated User for Running Scripts
Create a user with limited system permissions:
sudo adduser --disabled-password --gecos "" php_shell_user
Modify sudoers
to allow execution by this user:
php_shell_user ALL=(ALL) NOPASSWD: /scripts/safe_script.sh
Why Use a Dedicated User?
- Restricts PHP from running commands as root
- Reduces potential security impact
8. Preventing Shell Execution in PHP When Not Needed
If shell execution is not required, disable it in php.ini
:
disable_functions = exec, shell_exec, system, passthru
Why Disable Shell Execution?
- Prevents unauthorized command execution
- Hardens server security
9. Using Background Execution Securely
If a script needs to run in the background, redirect output and suppress errors:
shell_exec('nohup bash /scripts/task.sh > /dev/null 2>&1 &');
Why Use nohup?
- Prevents the script from terminating when PHP finishes execution
- Ensures long-running scripts execute safely
10. Best Practices for Securely Executing Shell Scripts in PHP
- Sanitize user input using
escapeshellarg()
- Restrict execution to only pre-approved scripts
- Use limited permissions and avoid running scripts as root
- Enable logging to track script execution
- Disable shell execution in PHP if not required
- Use sudo sparingly and restrict commands in
sudoers
- Run scripts under a dedicated user with minimal privileges
Conclusion
Securely executing shell scripts in PHP requires proper input sanitization, permission management, execution restrictions, and monitoring.
This guide covered:
- Preventing command injection vulnerabilities
- Whitelisting scripts for execution
- Setting proper permissions and restricting sudo access
- Logging and tracking executed scripts
- Using a dedicated user for script execution
By following these best practices, PHP applications can run shell scripts securely while minimizing security risks.