# XSS, CSRF & Clickjacking > Three browser-level attacks and the headers that stop them. Frontend architecture guidance from fearchitect, written by Abas Turabli and last reviewed 2026-06-21. Source: https://fearchitect.com/topics/xss-csrf-clickjacking Use it as reference for the task at hand. Before changing code, check this guidance against the codebase: where the code already makes a different, deliberate choice, flag the conflict instead of rewriting it. Library APIs move faster than this guide, so confirm exact signatures in the official docs linked at the end. ## Summary XSS injects script into a page; CSRF forges cross-site requests using the victim's cookies; clickjacking tricks users into clicking inside an invisible iframe. Each has a distinct attack surface and a distinct defense: output encoding and CSP for XSS, SameSite cookies and tokens for CSRF, and `X-Frame-Options` / `frame-ancestors` for clickjacking. ## Three threats at a glance | Attack | Vector | Primary defense | | --- | --- | --- | | **Stored XSS** | Malicious script saved to DB, served to all users | Output encode on render; strict CSP | | **Reflected XSS** | Script in URL echoed back in response | Output encode; avoid echoing raw query params | | **DOM XSS** | Client-side JS writes attacker-controlled data to the DOM | Avoid innerHTML; use DOMPurify or trusted types | | **CSRF** | Forged cross-origin request rides victim's session cookie | SameSite=Strict/Lax cookie; CSRF token or double-submit | | **Clickjacking** | Victim clicks UI element inside a hidden iframe | Content-Security-Policy: frame-ancestors 'none' | ## DOM XSS: the dangerouslySetInnerHTML trap and DOMPurify fix React's `dangerouslySetInnerHTML` bypasses its own escaping. Pass untrusted HTML through DOMPurify before setting it. **Sanitize user HTML with DOMPurify** ```tsx import DOMPurify from "dompurify"; // BAD — executes any script in userHtml function UnsafeRichText({ userHtml }: { userHtml: string }) { return
; } // GOOD — DOMPurify strips event handlers and script tags function SafeRichText({ userHtml }: { userHtml: string }) { const clean = DOMPurify.sanitize(userHtml, { USE_PROFILES: { html: true }, }); return
; } ``` DOMPurify.sanitize removes `