iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Exercises

Hands-on practice in a defensive frame: each exercise is a vulnerable snippet plus the task of writing the fix. Run them in an authorised lab only. Working through the exercises is the fastest way to build the intuition that turns code review into a fast pattern-match.

Fix four vulnerable snippets

EXAMPLE
<!-- ============================================================
     Exercise 1 — Reflected XSS in a PHP search box
     The page echoes $_GET['q'] back as the HTML title.
     ============================================================ -->

<!-- VULNERABLE (do NOT ship) -->
<?php
$q = $_GET['q'] ?? '';
?>
<h1>Results for <?= $q ?></h1>

<!-- YOUR TASK: rewrite the echo so it cannot inject HTML. -->
<!-- SOLUTION:
<?php $q = $_GET['q'] ?? ''; ?>
<h1>Results for <?= htmlspecialchars($q, ENT_QUOTES | ENT_HTML5, 'UTF-8') ?></h1>
-->

<!-- ============================================================
     Exercise 2 — DOM XSS via location.hash
     The current code reads the URL fragment and inserts it as HTML.
     ============================================================ -->

<div id='greeting'></div>
<script>
  // VULNERABLE
  document.getElementById('greeting').innerHTML =
    'Hello, ' + decodeURIComponent(location.hash.slice(1));
</script>

<!-- YOUR TASK: render the fragment as TEXT, not HTML. -->
<!-- SOLUTION:
<script>
  document.getElementById('greeting').textContent =
    'Hello, ' + decodeURIComponent(location.hash.slice(1));
</script>
-->

<!-- ============================================================
     Exercise 3 — Stored XSS in a Blade comment field
     A user-supplied comment is echoed with the raw {!! !!} operator.
     ============================================================ -->

{{-- VULNERABLE --}}
<div class='comment-body'>{!! $comment->body !!}</div>

{{-- YOUR TASK: render the comment safely. If you NEED some HTML
     (bold, italic, links), sanitise it instead of escaping. --}}

{{-- SOLUTION 1: plain text only (safest) --}}
{{-- <div class='comment-body'>{{ $comment->body }}</div> --}}

{{-- SOLUTION 2: allow a small whitelist via HTMLPurifier --}}
{{-- <div class='comment-body'>{!! $purifier->purify($comment->body) !!}</div> --}}

<!-- ============================================================
     Exercise 4 — JSON drop into a script block
     Server-side data passed into a JS variable is escaped as HTML
     but NOT for the JS string literal context.
     ============================================================ -->

<script>
  // VULNERABLE — htmlspecialchars is NOT enough here
  const user = '<?= htmlspecialchars($user_name, ENT_QUOTES, 'UTF-8') ?>';
</script>

<!-- YOUR TASK: produce a value safe for a JS string literal. -->
<!-- SOLUTION: json_encode with flags makes the value safe both as
     HTML and as a JS string. -->
<script>
  const user = <?= json_encode($user_name,
                JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT) ?>;
</script>

<!-- ============================================================
     Bonus drill — CSP
     Imagine you added a Content-Security-Policy with 'default-src self'.
     Which of the four bugs above does CSP still NOT prevent?
     ============================================================ -->

<!-- Answer: NONE of them. CSP would block inline scripts loaded by an
     attacker via injection, but Exercises 1 and 2 inject HTML, not
     <script> tags. Always escape correctly even with CSP in place. -->

Why it matters

Stored XSS is the variant that scales — one bad comment can attack every reader. Treat any code path that echoes user-saved data without context-correct escaping as a high-severity bug, regardless of how rarely the endpoint is hit.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
// Fill in: el.____ = userInput;   // safe text assignment
Try it Yourself »

Discussion

Loading…