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

Bootcamp

A guided 60-minute bootcamp for spotting and fixing XSS in your codebase. Run through the steps in order on a real branch; by the end you will have audited a feature, fixed the bugs, and shipped a CSP that prevents the next class of bugs from reaching production.

A 60-minute XSS bootcamp on a real codebase

EXAMPLE
# ===== Bootcamp objectives =====
# 1. Audit one feature for XSS sinks
# 2. Fix every bug found
# 3. Ship a Content-Security-Policy that hardens defaults

# ===== 0–5 min: scope the audit =====
# Pick ONE feature (search results page, comment thread, product review).
# Identify all input + output points.
# A feature with auth + UGC is the highest-yield target.

# ===== 5–25 min: find the sinks =====
# A 'sink' is a place where data lands in the DOM or HTML response.
# Grep for them in priority order:

# JavaScript sinks
git grep -nE "\\.(innerHTML|outerHTML|insertAdjacentHTML)\\s*="
git grep -nE "document\\.write\\("
git grep -nE "eval\\(|new Function\\("
git grep -n 'dangerouslySetInnerHTML'             # React
git grep -nE 'v-html'                             # Vue
git grep -nE 'bypassSecurityTrust'                # Angular

# Server-side sinks
git grep -nE '\$_GET|\$_POST|\$_REQUEST' -- '*.php'        # raw superglobals
git grep -n '\{\!\! '                              # Blade raw echo
git grep -nE 'Markup\\(' -- '*.py'                # Jinja2 Markup escape-hatch
git grep -n 'innerText' -- '*.html'               # often used WHERE textContent is right

# For each hit, ask: 'where does this value come from?' Trace upstream.
# If ANY part of the chain is user-controlled and not context-correct
# escaped, flag it for fix.

# ===== 25–45 min: fix the bugs =====
# Apply the right encoding for each output context.

# HTML body / text context:
#   PHP:    echo htmlspecialchars($v, ENT_QUOTES | ENT_HTML5, 'UTF-8');
#   Blade:  {{ $v }}              (NOT {!! !!})
#   React:  {value}                (NOT dangerouslySetInnerHTML)
#   Vue:    {{ value }}            (NOT v-html)

# HTML attribute context:
#   PHP:    htmlspecialchars($v, ENT_QUOTES, 'UTF-8')  with quoted attribute
#   React:  attr={value}           (React escapes attrs automatically)

# JavaScript string literal:
#   PHP:    json_encode($v, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT)
#   JS:     never inject server data into <script>; use data-* attributes

# URL parameter:
#   PHP:    urlencode($v)
#   JS:     encodeURIComponent(v)

# If you must allow SOME HTML (rich text comments), sanitise:
#   PHP:    HTMLPurifier
#   JS:     DOMPurify.sanitize(html, { USE_PROFILES: { html: true } })

# ===== 45–55 min: ship a Content-Security-Policy =====
# CSP is the safety net for the bugs you will write next.
# Start STRICT and relax only if monitoring tells you to.

# Response header (Laravel middleware shown):
# class CspMiddleware {
#   public function handle($req, $next) {
#     $nonce = base64_encode(random_bytes(16));
#     view()->share('cspNonce', $nonce);
#     $res = $next($req);
#     $res->headers->set('Content-Security-Policy',
#       "default-src 'self'; " .
#       "script-src 'self' 'nonce-$nonce'; " .
#       "style-src 'self' 'nonce-$nonce'; " .
#       "img-src 'self' data: https:; " .
#       "font-src 'self' data:; " .
#       "connect-src 'self' https://api.example.com; " .
#       "frame-ancestors 'none'; " .
#       "base-uri 'self'; " .
#       "object-src 'none'; " .
#       "require-trusted-types-for 'script';"
#     );
#     return $res;
#   }
# }

# In templates:
#   <script nonce="{{ $cspNonce }}">...</script>

# ===== 55–60 min: enforce in CI =====
# Add a CSP-report-uri / report-to endpoint to monitor violations.
# Run an XSS-focused SAST rule (see the 'xss/sast' lesson) on every PR.
# Mark CSP violations from production as P2 tickets — they often surface
# the next bug class before it becomes a customer report.

Why it matters

A nonce-based CSP makes most XSS bugs unexploitable — even if attacker-controlled HTML lands on the page, the browser refuses to execute injected `