Quiz
Six XSS questions that surface in code review. Pick the right defence for the context. Answers explain why each works.
Six XSS design questions
EXAMPLE
# ============================================================
# Q1) Server-side template echoing a query parameter
# ============================================================
# QUESTION: which encoder for <h1>Results for <?= ... ?></h1>?
#
# ANSWER: htmlspecialchars($value, ENT_QUOTES | ENT_HTML5, 'UTF-8')
# The context is HTML BODY; the right encoder for HTML body is htmlspecialchars.
# ============================================================
# Q2) Same value, but inside <a title='...'>
# ============================================================
# QUESTION: same encoder?
#
# ANSWER: yes, htmlspecialchars — BUT the attribute MUST be quoted (single or
# double). Unquoted attributes are XSS-vulnerable regardless of encoding.
# ============================================================
# Q3) Inserting a server value into a <script> tag
# ============================================================
# QUESTION: <script>const user = '<?= ... ?>';</script>
#
# ANSWER: htmlspecialchars is WRONG here — JS string literal context.
# Use json_encode with safe flags:
# <script>const user = <?= json_encode($user,
# JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT) ?>;</script>
# Better: avoid mixing data into script tags; use data-* attributes + JS read.
# ============================================================
# Q4) React's dangerouslySetInnerHTML — when to use it?
# ============================================================
# ANSWER: almost never.
# - User-supplied content -> sanitise with DOMPurify FIRST
# - Server-supplied trusted HTML (eg server-rendered Markdown) -> ok
# Even then, attach a code comment with the justification so reviewers know it
# is deliberate.
# ============================================================
# Q5) DOM-based XSS in 'document.title = location.hash.slice(1)'
# ============================================================
# QUESTION: is this XSS?
#
# ANSWER: setting document.title to a string does NOT render HTML — that
# specific line is safe. Bug would be:
# document.getElementById('out').innerHTML = location.hash.slice(1);
# Use textContent (or .innerText) instead.
# ============================================================
# Q6) Content-Security-Policy — minimum useful?
# ============================================================
# ANSWER:
# Content-Security-Policy:
# default-src 'self';
# script-src 'self' 'nonce-r4nd0m';
# style-src 'self' 'nonce-r4nd0m';
# object-src 'none';
# base-uri 'self';
# frame-ancestors 'self';
# require-trusted-types-for 'script';
# Combined with HttpOnly+Secure+SameSite cookies, this turns most XSS bugs
# into 'attempted exploit found in CSP report' rather than 'breach'.
# ============================================================
# Bonus — what is the most common false fix?
# ============================================================
# ANSWER: 'I'll strip <script> tags with a regex.'
# Browsers parse HTML in many ways (img onerror, svg onload, javascript: URIs,
# data: URIs, encoded entities). Use a real sanitiser (DOMPurify, HTMLPurifier)
# or, better, escape the output for the context you are in.
# ============================================================
# Scoring
# ============================================================
# 6 / 6 -> can lead an XSS code review
# 4 / 6 -> revisit xss/cheatsheet
# < 4 -> read OWASP XSS Prevention Cheat Sheet
Why it matters
Pick the encoder by CONTEXT, not by habit. HTML body, attribute, JS string, URL parameter — each has its own correct encoder. A nonce-based CSP + Trusted Types is the safety net; correct contextual encoding everywhere is the primary defence. Together they make XSS bugs rare enough that the rest of your security work matters.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Discussion
Loading…