Security in React (XSS & dangerouslySetInnerHTML)

5 questions found

What is cross site scripting, often called XSS, and how does React protect against it by default?

Beginner
Cross site scripting happens when an attacker manages to inject malicious code into a page, which then runs in another user's browser, often stealing information or performing unwanted actions. React protects against this automatically by treating any text you display through normal JSX as plain text, safely escaping special characters instead of running them as code.
function Comment({ text }) {
  return <p>{text}</p>; // React automatically escapes this text safely
}

// Even if text contains something like <script>alert('hacked')</script>
// React will safely display it as plain visible text, not run it as actual code
Real-world example A blog's comment section safely displays user submitted comments containing suspicious looking text, because React automatically escapes it as plain text instead of accidentally running it as real code in another visitor's browser.

Common follow-ups: What specifically does React do differently from directly inserting text into the DOM using plain JavaScript?;Are there any situations where React's automatic protection does not apply?

Error Handling;Forms: Controlled & Uncontrolled Components

What is dangerouslySetInnerHTML and why does its name include the word dangerously?

Intermediate
dangerouslySetInnerHTML lets you insert raw HTML directly into a component, bypassing React's normal automatic protection against cross site scripting. The name is a clear warning that using it incorrectly, especially with content coming from users, can open your app up to serious security vulnerabilities.
function Article({ htmlContent }) {
  return <div dangerouslySetInnerHTML={{ __html: htmlContent }} />;
}

// Only ever use this with trusted, sanitized content, never raw user input directly
Real-world example A blogging platform uses dangerouslySetInnerHTML to display rich formatted article content written by trusted staff writers, while completely avoiding this approach for anything submitted by anonymous website visitors.

Common follow-ups: How would you safely sanitize untrusted HTML before using dangerouslySetInnerHTML?;What popular libraries help clean potentially unsafe HTML before displaying it?

Design Patterns in React;Error Boundaries

How would you safely display user generated HTML content, such as a rich text comment, without exposing your app to XSS attacks?

Advanced
You use a trusted sanitization library, like DOMPurify, to clean the HTML first, removing any dangerous scripts or unsafe attributes, before ever passing the result into dangerouslySetInnerHTML. This lets you safely support formatted content like bold text or links while blocking anything genuinely harmful.
import DOMPurify from 'dompurify';

function Comment({ rawHtml }) {
  const cleanHtml = DOMPurify.sanitize(rawHtml);
  return <div dangerouslySetInnerHTML={{ __html: cleanHtml }} />;
}
Real-world example A forum allows users to write formatted comments using basic HTML tags like bold and italics, safely cleaning every comment through DOMPurify before displaying it, blocking any hidden malicious script a bad actor might try to sneak in.

Common follow-ups: What specific kinds of malicious content does a library like DOMPurify actually remove?;Is sanitizing on the server, in addition to the client, also recommended for extra safety?

Data Fetching (React Query & SWR);Forms: Controlled & Uncontrolled Components

Why should you avoid storing sensitive information, like an authentication token, directly in your React app's regular JavaScript state or a global variable?

Intermediate
Data kept only in memory disappears the moment the page reloads, but more importantly, any sensitive token accessible to your app's JavaScript can potentially be read by malicious code if your app is ever vulnerable to a cross site scripting attack. Storing sensitive tokens in a properly configured cookie that JavaScript cannot access at all offers stronger protection.
// Less secure, readable by any JavaScript running on the page, including malicious code
localStorage.setItem('authToken', token);

// More secure, the browser sends this cookie automatically, but JavaScript cannot read its value
// (this cookie must be set by the server with the HttpOnly flag)
Real-world example A banking app avoids storing its authentication token in a place JavaScript can read, choosing instead to rely on a secure cookie set by the server, reducing the damage a successful cross site scripting attack could cause.

Common follow-ups: What does the HttpOnly flag on a cookie actually prevent JavaScript from doing?;What other common security practices should a React app follow alongside this one?

Authentication;Environment Variables & Configuration

Why is it risky to build a link's web address directly from user input without checking it first?

Beginner
A malicious user could enter something like javascript colon followed by harmful code instead of a normal web address, and if that value is used directly as a link's destination, clicking it could run that harmful code. Always validate that a URL actually starts with an expected protocol, like https, before using it as a link.
function isSafeUrl(url) {
  return url.startsWith('https://') || url.startsWith('/');
}

function UserLink({ url, label }) {
  if (!isSafeUrl(url)) return <span>{label}</span>;
  return <a href={url}>{label}</a>;
}
Real-world example A profile page that lets users add a personal website link checks that the submitted address actually starts with https before turning it into a real clickable link, blocking a common trick attackers use to run harmful code.

Common follow-ups: What other user submitted values besides links need similar careful checking before use?;How would a security review test whether this kind of protection is actually working?

Forms: Controlled & Uncontrolled Components;Error Handling