RSTR-INJ-006 — PHP SQL query built from request superglobal

Summary

A PHP database call (mysqli_query, pg_query, $pdo->query(), etc.) concatenates $_GET[...], $_POST[...], $_REQUEST[...], or $_COOKIE[...] directly into the SQL string. Classic SQL injection — an attacker submits ' OR 1=1 -- and reads or rewrites the entire table.

Severity

Critical.

Languages

PHP.

What rastray flags

Procedural API:

$rows = mysqli_query($db,
    "SELECT * FROM users WHERE id = " . $_GET['id']);    // ← flagged
pg_query($conn,
    "DELETE FROM orders WHERE name = '" . $_POST['name'] . "'");  // ← flagged

Object-style PDO / mysqli:

$rows = $pdo->query(
    "SELECT * FROM logs WHERE pat = '" . $_REQUEST['pat'] . "'");  // ← flagged

What rastray deliberately does not flag

  • Calls where the SQL is a constant string with no superglobal interpolation.
  • Calls where the value flows through an intermediate variable (consistent with how every other rastray rule scopes its pattern match).
  • Prepared-statement use: $pdo->prepare(...) + ->execute([...]).

How to fix it

Use prepared statements with placeholders. With PDO:

$stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id');
$stmt->execute(['id' => $_GET['id']]);
$rows = $stmt->fetchAll();

With mysqli:

$stmt = mysqli_prepare($db, 'SELECT * FROM users WHERE id = ?');
mysqli_stmt_bind_param($stmt, 'i', $_GET['id']);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);

For Postgres (pg_query_params):

$result = pg_query_params(
    $conn,
    'SELECT * FROM orders WHERE name = $1',
    [$_POST['name']]
);

Placeholders are the only safe form. Sanitising with mysqli_real_escape_string helps but is easy to misuse (it does not escape numeric contexts, table names, or column names); prepared statements remove the foot-gun.

References