RSTR-XSS-006 — PHP echo / print of request superglobal

Summary

A PHP page writes $_GET[...], $_POST[...], $_REQUEST[...], or $_COOKIE[...] directly into the HTTP response via echo, print, or the short-echo <?= ?> form. No HTML escaping in between — the attacker's input is parsed as HTML in the page's origin, yielding reflected (and sometimes stored) XSS.

Severity

High.

Languages

PHP.

What rastray flags

<?php echo $_GET['name']; ?>                                 <!-- ← flagged -->
<?php print "Hello " . $_POST['name']; ?>                    <!-- ← flagged -->
<p><?= $_REQUEST['msg'] ?></p>                               <!-- ← flagged -->

What rastray deliberately does not flag

  • Values run through htmlspecialchars(...) first:

    <?= htmlspecialchars($_GET['name'], ENT_QUOTES, 'UTF-8') ?>
    

    The regex deliberately requires the superglobal to appear before any opening ( on the line, so function-wrapped uses are excluded.

  • Values rendered through Twig / Blade / Smarty templates with auto-escaping on.

How to fix it

Always escape on output. The canonical helper for HTML context is htmlspecialchars with ENT_QUOTES and an explicit charset:

<p>Hello, <?= htmlspecialchars($_GET['name'], ENT_QUOTES, 'UTF-8') ?>!</p>

For an attribute, the same call works because ENT_QUOTES escapes both single and double quotes:

<a href="<?= htmlspecialchars($_GET['url'], ENT_QUOTES, 'UTF-8') ?>">link</a>

For URL contexts (only the path / query of a URL):

<a href="/search?q=<?= rawurlencode($_GET['q']) ?>">search</a>

For JavaScript contexts (a value embedded inside an inline <script>):

<script>
const user = <?= json_encode($_GET['user'], JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT) ?>;
</script>

If your project uses a template engine (Twig, Blade), prefer those: auto-escape is on by default and the per-call helper disappears.

References