RSTR-INJ-007 — PHP command exec on request superglobal
Summary
A PHP shell-out function (exec, system, shell_exec, passthru,
popen, proc_open, pcntl_exec) or the backtick operator runs a
command built from $_GET, $_POST, $_REQUEST, or $_COOKIE.
An attacker injects ; / && / $(...) and runs arbitrary OS
commands as the web user.
Severity
Critical.
Languages
PHP.
What rastray flags
exec("ping -c 4 " . $_GET['host']); // ← flagged
system("ls " . $_POST['dir']); // ← flagged
shell_exec("grep " . $_REQUEST['q'] . " /var/log/syslog"); // ← flagged
passthru("zip -r out.zip " . $_GET['target']); // ← flagged
$out = `ls -la $_GET[d]`; // ← flagged (backticks)
What rastray deliberately does not flag
- Constant-string commands:
exec('/usr/bin/uptime'). - Indirect flow (
$host = $_GET['host']; exec("ping $host")— same one-step taint scope as the rest of rastray). - Arguments passed via
escapeshellarg(...)inside the call. The rule still fires (the regex cannot inspect arguments); suppress per-line if you can prove the escape is correct.
How to fix it
The reliable answer is don't shell out. PHP has libraries for
common tasks (gethostbyname for DNS, Imagick for image work,
etc.). When you must, build the command from a fixed allow-list
and quote variable parts with escapeshellarg:
$ALLOWED_HOSTS = ['example.com', 'api.example.com'];
if (!in_array($_GET['host'], $ALLOWED_HOSTS, true)) {
http_response_code(400);
exit;
}
$out = shell_exec('ping -c 4 ' . escapeshellarg($_GET['host']));
escapeshellarg puts the value inside single quotes and escapes any
existing single quotes, so shell metacharacters lose their meaning.
It is not a substitute for an allow-list, just defence in depth.
How to suppress
If the call is genuinely safe after explicit escaping or because the input source is trusted:
// rastray-ignore: RSTR-INJ-007 — internal cron, $_REQUEST is loopback-only
exec('rsync -a ' . escapeshellarg($_REQUEST['src']) . ' /backup/');