Help us improve
Share bugs, ideas, or general feedback.
From acc
Analyzes PHP code for command injection vulnerabilities. Detects unsafe shell_exec, exec, system, passthru, backticks, popen/proc_open with user input and missing escapeshellarg/escapeshellcmd.
npx claudepluginhub dykyi-roman/awesome-claude-code --plugin accHow this skill is triggered — by the user, by Claude, or both
Slash command
/acc:check-command-injectionThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Analyze PHP code for OS command injection vulnerabilities (OWASP A03:2021).
Detects OS command injection in JavaScript, TypeScript, Python, Go, Ruby, PHP via shell sinks like exec/system/popen. Traces user input, checks sanitization/argument injection for RCE in CLI wrappers.
Detects path traversal vulnerabilities in PHP code including directory traversal, LFI/RFI, file uploads, symlink attacks, zip slip, and null byte injection.
Automatically scans code for security vulnerabilities like XSS, SQL injection, CSRF, and authentication flaws.
Share bugs, ideas, or general feedback.
Analyze PHP code for OS command injection vulnerabilities (OWASP A03:2021).
// CRITICAL: shell_exec with user input
$output = shell_exec("ls " . $_GET['dir']);
$output = shell_exec("ping -c 3 {$host}");
// CRITICAL: exec with user input
exec("convert " . $filename . " output.png", $output);
exec("grep '$search' /var/log/app.log");
// CRITICAL: system with user input
system("cat " . $logFile);
system("tar -xzf $archive");
// CRITICAL: passthru with user input
passthru("ffmpeg -i $videoFile output.mp4");
// CRITICAL: proc_open with user input
$process = proc_open("mail -s '$subject' $email", $descriptors, $pipes);
// CRITICAL: Backticks with variables
$result = `ls $directory`;
$output = `grep $pattern $file`;
$data = `curl $url`;
// CRITICAL: Backticks in string
$files = `find /uploads -name "*{$extension}"`;
// CRITICAL: popen with user input
$handle = popen("sort " . $filename, "r");
// CRITICAL: proc_open with user input
$descriptors = [
0 => ['pipe', 'r'],
1 => ['pipe', 'w'],
2 => ['pipe', 'w'],
];
$process = proc_open("php $script", $descriptors, $pipes);
// CRITICAL: String concatenation
$cmd = "convert " . $input . " -resize " . $size . " " . $output;
shell_exec($cmd);
// CRITICAL: sprintf without escaping
$cmd = sprintf("mysqldump -u%s -p%s %s", $user, $password, $database);
exec($cmd);
// CRITICAL: implode for arguments
$args = implode(' ', $userInputArray);
shell_exec("process $args");
// VULNERABLE: No escapeshellarg
exec("ls " . $directory); // Should be escapeshellarg($directory)
// VULNERABLE: No escapeshellcmd
$cmd = $_GET['cmd'];
shell_exec($cmd); // Should be escapeshellcmd($cmd)
// WRONG: Escaping entire command instead of arguments
shell_exec(escapeshellarg("ls $dir")); // Entire command escaped, won't work
// CORRECT: Escape arguments only
shell_exec("ls " . escapeshellarg($dir));
// CRITICAL: Filename injection
$filename = $_FILES['upload']['name'];
shell_exec("process " . $filename);
// Filename: "file.txt; rm -rf /"
// CRITICAL: Environment variable injection
putenv("PATH=" . $_GET['path']);
// Later: shell_exec("mycommand"); uses modified PATH
// CRITICAL: Argument injection via flags
$format = $_GET['format'];
exec("convert input.png --format=$format output");
// format: "png --help" or "png; rm -rf /"
// CRITICAL: ImageMagick with user input
exec("convert " . $uploadedFile . " -resize 100x100 thumb.png");
// CRITICAL: Ghostscript
shell_exec("gs -dBATCH -sDEVICE=pdfwrite -sOutputFile=merged.pdf $files");
// CRITICAL: ffmpeg
passthru("ffmpeg -i " . $videoUrl . " -c:v libx264 output.mp4");
// CRITICAL: Git with user input
exec("git clone " . $repoUrl);
exec("git checkout " . $branch);
shell_exec("git log --author='$author'");
// CRITICAL: SVN
exec("svn checkout " . $svnUrl);
// CRITICAL: mail() fifth parameter
mail($to, $subject, $message, $headers, "-f$from");
// $from could contain: "attacker@evil.com -X/var/www/shell.php"
// CRITICAL: sendmail
exec("sendmail -t < " . $emailFile);
// CRITICAL: mysqldump with user credentials
$cmd = "mysqldump -u{$user} -p{$pass} {$database}";
exec($cmd);
// Password could contain: "pass' | cat /etc/passwd #"
// CRITICAL: psql
exec("psql -U {$user} -d {$database} -c '{$query}'");
# Command execution functions
Grep: "(shell_exec|exec|system|passthru|popen|proc_open)\s*\(" --glob "**/*.php"
# Backticks with variables
Grep: "`[^`]*\\\$[^`]*`" --glob "**/*.php"
# Command building with variables
Grep: "(shell_exec|exec|system)\s*\([^)]*\.\s*\\\$" --glob "**/*.php"
# Missing escape functions
Grep: "(shell_exec|exec)\s*\([^)]*(?!escapeshell)" --glob "**/*.php"
// SECURE: Escape each argument
$safeDir = escapeshellarg($directory);
$output = shell_exec("ls $safeDir");
// SECURE: Multiple arguments
$cmd = sprintf(
"convert %s -resize %s %s",
escapeshellarg($input),
escapeshellarg($size),
escapeshellarg($output)
);
exec($cmd);
// SECURE: Escape special characters in command
$cmd = escapeshellcmd($userCommand);
shell_exec($cmd);
// Note: escapeshellcmd escapes: &#;`|*?~<>^()[]{}$\, \x0A, \xFF
// Does NOT prevent argument injection
// SECURE: Whitelist allowed commands
final class SafeCommandExecutor
{
private const ALLOWED_COMMANDS = [
'convert',
'ffmpeg',
'gs',
];
public function execute(string $command, array $args): string
{
if (!in_array($command, self::ALLOWED_COMMANDS, true)) {
throw new SecurityException('Command not allowed');
}
$safeArgs = array_map('escapeshellarg', $args);
$cmd = $command . ' ' . implode(' ', $safeArgs);
return shell_exec($cmd) ?? '';
}
}
// SECURE: Symfony Process component
use Symfony\Component\Process\Process;
$process = new Process(['ls', '-la', $directory]);
$process->run();
// Arguments are automatically escaped
// SECURE: With timeout and error handling
$process = new Process(['convert', $input, '-resize', $size, $output]);
$process->setTimeout(30);
$process->run();
if (!$process->isSuccessful()) {
throw new ProcessFailedException($process);
}
// AVOID: Shell command for file operations
shell_exec("rm " . escapeshellarg($file));
// BETTER: PHP function
unlink($file);
// AVOID: Shell for directory listing
$files = shell_exec("ls $dir");
// BETTER: PHP function
$files = scandir($dir);
// AVOID: Shell for file reading
$content = shell_exec("cat " . escapeshellarg($file));
// BETTER: PHP function
$content = file_get_contents($file);
| Pattern | Severity | CWE |
|---|---|---|
| exec/shell_exec with $_GET/$_POST | 🔴 Critical | CWE-78 |
| Backticks with user variable | 🔴 Critical | CWE-78 |
| Missing escapeshellarg | 🔴 Critical | CWE-78 |
| mail() fifth parameter injection | 🔴 Critical | CWE-78 |
| Environment variable injection | 🟠 Major | CWE-78 |
| Filename in command | 🟠 Major | CWE-78 |
### Command Injection: [Description]
**Severity:** 🔴 Critical
**Location:** `file.php:line`
**CWE:** CWE-78 (OS Command Injection)
**Issue:**
User input is passed directly to shell command without escaping.
**Attack Vector:**
1. Input: `file.txt; cat /etc/passwd`
2. Executed: `process file.txt; cat /etc/passwd`
3. Attacker reads system files
**Code:**
```php
// Vulnerable
exec("process " . $filename);
Fix:
// Secure: Use escapeshellarg
exec("process " . escapeshellarg($filename));
// Better: Use Process component
$process = new Process(['process', $filename]);
$process->run();
References: