Question presented to candidate: "How much XSS protection do you get from React for free, and where does it stop?"
What a strong answer should cover:
- Auto-escaping: any value interpolated with
{}is escaped to text, so it can never become markup. This covers the overwhelming majority of XSS risk. - Why it works: JSX produces elements as data, and React sets text via
textContent-equivalent paths rather than parsing HTML. dangerouslySetInnerHTMLis the deliberate opt-out, named to create friction. It genuinely injects.- URL-based XSS: React 19 blocks
javascript:URLs inhrefby rewriting them into a throwing expression. Older React only warned. - Still your responsibility: user-controlled URLs generally (validate the protocol), server-rendered data injected into the HTML shell,
<script>/<style>content, and third-party markup. - Sanitise before rendering HTML you must render — DOMPurify — and prefer a Content-Security-Policy as defence in depth.
- Server-side: escaping JSON embedded in the HTML document, and never trusting
__htmlbuilt from user input.
Clarifying questions expected:
- "Are we rendering user-supplied HTML anywhere, or only text?"
- "Is this client-rendered or server-rendered? SSR adds the HTML-shell injection surface."
Code / implementation expected: Optional. Showing the escaped-versus-dangerouslySetInnerHTML contrast makes the boundary concrete.