JSX auto-escapes values to prevent XSS by default, but dangerouslySetInnerHTML, href='javascript:', and localStorage token storage are common vulnerability vectors that require explicit mitigation.
All values in {} are escaped before rendering — prevents the most common XSS attacks by treating user input as text, not HTML.
dangerouslySetInnerHTML bypasses escaping (sanitize with DOMPurify), href='javascript:' executes code, and compromised npm packages run with full access.
localStorage is vulnerable to XSS (any script can read it). httpOnly + Secure + SameSite cookies prevent JavaScript access to tokens.
React doesn't prevent CSRF — use server-generated tokens in custom headers and SameSite cookie attributes.
CSP headers restrict script sources, blocking inline scripts and third-party injection — the strongest browser-level XSS defense.
React provides built-in XSS protection through JSX auto-escaping, but a secure React application requires understanding additional attack vectors and defense strategies.
JSX escapes all values embedded in curly braces before rendering to the DOM. If a user enters <script>alert('xss')</script> and you render {userInput}, React treats it as text, not HTML. This prevents the most common XSS attack vector — injecting malicious scripts through user input.
dangerouslySetInnerHTML: This prop deliberately bypasses escaping to render raw HTML. If the HTML comes from user input or untrusted sources, it must be sanitized first. Use DOMPurify: <div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(userHTML) }} />.
href and src attributes: React does not sanitize URL attributes. <a href={userInput}> can execute JavaScript if the user provides javascript:alert('xss'). Validate URLs: ensure they start with https:// or /, and never use user input directly in href or src without validation.
Third-party dependencies: NPM packages can contain malicious code. A compromised dependency runs with full access to your app. Regularly audit with npm audit, use Snyk or Dependabot, and minimize dependencies.
React doesn't prevent CSRF — it's a UI library, not a security framework. CSRF attacks trick authenticated users into making unwanted requests. Defense:
X-CSRF-Token) with every mutation requestSameSite=Strict or Lax) prevents cookies from being sent on cross-site requestslocalStorage is accessible to any JavaScript running on the page — a single XSS vulnerability lets an attacker steal tokens. More secure approach:
HttpOnly flag so JavaScript cannot access the cookie. Set Secure to require HTTPS. Set SameSite=Strict to prevent CSRF.CSP HTTP headers restrict which scripts can run on the page. Content-Security-Policy: script-src 'self' only allows scripts from your own domain, blocking inline scripts and third-party injection. Requires nonce or hash attributes for legitimate inline scripts. CSP is the strongest browser-level defense against XSS.
eval() and new Function() — they execute arbitrary strings as codeReact auto-escapes JSX values (built-in XSS protection) but dangerouslySetInnerHTML, URL attributes, and third-party deps are still vectors. Use httpOnly cookies over localStorage for auth tokens. CSP headers are the strongest client-side defense. React is a UI library — CSRF, authentication, and server-side validation are not its responsibility.
Fun Fact
React intentionally named the prop 'dangerouslySetInnerHTML' to be scary and verbose — the React team wanted developers to think twice before using it. The __html key inside the object is another speed bump: it forces you to write { __html: ... } instead of just passing a string, making accidental unsafe rendering harder.