Home JavaScript Security in React Applications
Advanced 6 min · July 13, 2026

Security in React Applications

XSS prevention, CSP headers, sanitization, secure auth patterns, and dependency auditing..

N
Naren Founder & Principal Engineer

20+ years shipping production JavaScript and front-end systems at scale. Notes here come from systems that actually shipped.

Follow
Verified
production tested
July 13, 2026
last updated
2,018
articles · all by Naren
Before you start⏱ 36 min read
  • Node.js 18+, React 18+, npm 9+, familiarity with JSX, hooks, and state management. Understanding of HTTP, cookies, and basic authentication flows.
Quick Answer

Security in React Applications: A core React concept for building modern user interfaces. It helps you structure your components efficiently and handle data flow predictably.

✦ Definition~90s read
What is Security in React Applications?

Security in React Applications is a fundamental concept in React development. It refers to the patterns, APIs, and best practices that React provides for building user interfaces. Understanding this concept is essential for writing clean, efficient, and maintainable React code. This tutorial covers everything from basic usage to advanced patterns with real-world examples.

React is a JavaScript library for building user interfaces.
Plain-English First

React is a JavaScript library for building user interfaces. This article covers security — a key concept for building modern web applications.

⚙ Browser compatibility
Latest versions — ✓ supported
ChromeFirefoxSafariEdge

A comprehensive guide to security in react applications with production examples and best practices.

The Threat Model for React Apps

Before writing any security code, you must understand what you're defending against. In React applications, the primary threats are Cross-Site Scripting (XSS), data injection, insecure direct object references (IDOR), and dependency vulnerabilities. XSS remains the most common: attackers inject malicious scripts via user input, URL parameters, or stored data. React's JSX escapes values by default, but dangerous patterns like dangerouslySetInnerHTML, eval, or direct DOM manipulation bypass this protection. Other vectors include prototype pollution through third-party libraries, open redirects via window.location, and sensitive data exposure in client-side bundles. A production app must assume the attacker controls the network, the browser, and any public API endpoint. This threat model drives every security decision: never trust user input, never expose secrets to the client, and always validate on the server.

ThreatModel.jsxJSX
1
2
3
4
5
6
7
8
9
10
11
12
// Example: XSS via dangerouslySetInnerHTML
const userComment = "<img src=x onerror=alert('XSS')>";

// Dangerous - never do this
function UnsafeComment() {
  return <div dangerouslySetInnerHTML={{ __html: userComment }} />;
}

// Safe - React escapes automatically
function SafeComment() {
  return <div>{userComment}</div>;
}
Output
SafeComment renders the literal string, not an image tag.
Try it live
⚠ dangerouslySetInnerHTML is a red flag
If you see this in a code review, treat it as a security incident. It's almost always avoidable with proper component design.
📊 Production Insight
We once had a stored XSS via a rich text editor that used dangerouslySetInnerHTML. The fix was to sanitize output with DOMPurify on both client and server.
🎯 Key Takeaway
Understand your threat model: XSS is the top risk, and React's default escaping is your first line of defense.
react-security THECODEFORGE.IO Securing React App Input Flow Step-by-step validation and sanitization pipeline User Input Received From forms, URLs, or APIs Client-Side Validation Check type, length, and format Sanitize Input Escape HTML entities and strip scripts Server-Side Validation Re-validate on backend Store or Render Use React's JSX escaping ⚠ Never trust client-side validation alone Always re-validate on the server THECODEFORGE.IO
thecodeforge.io
React Security

Input Validation and Sanitization

Input validation is your second line of defense. React apps receive input from forms, URL params, query strings, and WebSocket messages. Always validate on the client for UX, but never rely on it for security — server validation is mandatory. For client-side sanitization, use libraries like DOMPurify when you must render HTML. For URLs, validate against a whitelist of allowed protocols (https:// only) and domains. For form inputs, enforce type, length, and pattern constraints. Avoid using eval, new Function(), or setTimeout(string) — these are code injection vectors. Use a schema validator like Zod or Yup to enforce input shapes. Remember: validation is about rejecting bad data, not cleaning it. If you can't validate, reject.

validation.tsTYPESCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { z } from 'zod';

const CommentSchema = z.object({
  body: z.string().min(1).max(1000),
  userId: z.string().uuid(),
  postId: z.string().uuid(),
});

export function validateComment(data: unknown) {
  const result = CommentSchema.safeParse(data);
  if (!result.success) {
    throw new Error('Invalid input');
  }
  return result.data;
}
Output
Throws if data doesn't match schema.
Try it live
💡Validate early, validate often
Add validation at every boundary: API calls, form submissions, URL parsing. Use Zod for runtime type checking.
📊 Production Insight
We had a bug where a user submitted a comment with 10,000 characters, crashing the rendering. Zod's max length check caught it before it hit the database.
🎯 Key Takeaway
Client-side validation is for UX; server-side validation is for security. Never trust the client.

Secure Authentication and Session Management

Authentication in React apps typically uses JWTs stored in localStorage or cookies. localStorage is vulnerable to XSS: if an attacker injects a script, they can steal the token. Use httpOnly, Secure, SameSite=Strict cookies for session tokens. This prevents JavaScript access and mitigates XSS token theft. For refresh tokens, use a separate cookie with a shorter lifespan. Implement CSRF protection using SameSite cookies or custom headers. Never store secrets like API keys in the client bundle — use environment variables on the server and proxy requests. For OAuth flows, use the Authorization Code flow with PKCE, never the implicit flow. Logout should invalidate tokens server-side.

auth.jsJAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
// Server-side cookie setting (Express example)
res.cookie('session', token, {
  httpOnly: true,
  secure: true,
  sameSite: 'strict',
  maxAge: 15 * 60 * 1000, // 15 minutes
});

// Client-side: no token in JS memory
// Use fetch with credentials: 'include'
fetch('/api/data', {
  credentials: 'include'
});
Output
Cookie is set with security flags; client cannot read it via JavaScript.
Try it live
⚠ Never store JWTs in localStorage
Any XSS vulnerability will leak the token. Use httpOnly cookies instead.
📊 Production Insight
We had a breach where an XSS in a third-party widget stole localStorage tokens. Switching to httpOnly cookies eliminated that vector.
🎯 Key Takeaway
Use httpOnly, Secure, SameSite cookies for session tokens. Never expose secrets to the client.
react-security THECODEFORGE.IO React Security Architecture Layers Defense-in-depth from UI to backend Presentation Layer React Components | JSX Escaping | CSP Headers State Management Redux/Zustand | Secure Storage | Data Minimization API Communication HTTPS | Token Auth | Input Validation Dependency Layer npm Audit | Snyk Scanning | Lock Files Backend Services Auth Server | Database | Logging THECODEFORGE.IO
thecodeforge.io
React Security

Protecting Against XSS in React

React's JSX escapes values, but there are edge cases. dangerouslySetInnerHTML is the obvious one, but also watch for: href attributes with javascript: URLs, onerror handlers in SVG, and style objects with user-controlled keys. Use npm audit and snyk to scan for vulnerable dependencies. For user-generated HTML, sanitize with DOMPurify on both client and server. Avoid using refs to directly manipulate the DOM — use React's declarative approach. For URL inputs, validate with new URL() and check protocol. For rich text editors, use libraries that output structured data (like Slate or TipTap) instead of raw HTML.

SafeLink.jsxJSX
1
2
3
4
5
6
7
8
9
10
11
12
13
function SafeLink({ url, children }) {
  // Validate URL
  let parsed;
  try {
    parsed = new URL(url);
  } catch {
    return <span>{children}</span>;
  }
  if (parsed.protocol !== 'https:') {
    return <span>{children}</span>;
  }
  return <a href={url} rel="noopener noreferrer">{children}</a>;
}
Output
Only renders anchor if URL is valid https.
Try it live
💡Sanitize URLs, not just HTML
javascript:alert(1) in an href is still XSS. Always validate URL protocol.
📊 Production Insight
A developer used user input in an href without validation, creating an open redirect. We added a URL validation utility used across all components.
🎯 Key Takeaway
React escapes JSX, but not all attributes. Validate URLs and sanitize HTML explicitly.

Dependency Management and Supply Chain Security

Your React app is only as secure as its dependencies. The npm ecosystem has thousands of packages, many with known vulnerabilities. Use npm audit regularly and integrate Snyk or Dependabot into your CI pipeline. Pin exact versions in package.json to avoid surprise updates. Use package-lock.json to ensure reproducible builds. For critical packages, consider forking and auditing the code. Avoid packages with unnecessary permissions or that eval code. Use tools like socket.dev to check package behavior. Regularly prune unused dependencies — fewer packages mean fewer attack vectors.

package.jsonJSON
1
2
3
4
5
6
7
8
9
10
{
  "dependencies": {
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "zod": "3.22.4"
  },
  "scripts": {
    "audit": "npm audit --audit-level=high"
  }
}
Output
Exact versions prevent unexpected updates.
🔥Supply chain attacks are rising
Malicious packages can steal environment variables or inject crypto miners. Audit every dependency.
📊 Production Insight
We had a build break because a transitive dependency introduced a breaking change. Pinning exact versions and using lockfiles prevented recurrence.
🎯 Key Takeaway
Pin exact versions, audit regularly, and remove unused dependencies.

Secure API Communication

All communication between React and your backend must be over HTTPS. Use fetch with credentials: 'include' for cookie-based auth. For APIs, use a consistent pattern: validate responses, handle errors gracefully, and never expose internal error details to the client. Implement rate limiting and input validation on the server. Use Content Security Policy (CSP) headers to restrict what resources can be loaded. For GraphQL, use persisted queries to prevent injection. Avoid embedding API keys in the client — use a BFF (Backend for Frontend) pattern to proxy requests.

api.jsJAVASCRIPT
1
2
3
4
5
6
7
8
9
10
async function fetchData(url) {
  const response = await fetch(url, {
    credentials: 'include',
    headers: { 'Content-Type': 'application/json' }
  });
  if (!response.ok) {
    throw new Error('Request failed');
  }
  return response.json();
}
Output
Sends cookies with request; throws on non-2xx.
Try it live
⚠ Never expose internal error messages
Stack traces in client responses are a goldmine for attackers. Always return generic errors.
📊 Production Insight
We saw an attacker probing our API by reading error messages. We switched to generic 'Internal server error' and added logging on the server.
🎯 Key Takeaway
Use HTTPS, httpOnly cookies, and a BFF pattern to secure API communication.

Content Security Policy (CSP)

CSP is a browser security mechanism that mitigates XSS and data injection attacks. It works by specifying which sources are allowed for scripts, styles, images, and other resources. For a React app, a strict CSP might allow only same-origin scripts and inline scripts with nonces. Use script-src 'self' and add nonces for inline scripts. Avoid 'unsafe-inline' and 'unsafe-eval'. For styles, use style-src 'self' and nonces. Report violations via report-uri or report-to. CSP can be tricky with React's development tools — test in production mode. Use csp-evaluator to check your policy.

csp.jsJAVASCRIPT
1
2
3
4
5
6
7
8
// Express middleware example
app.use((req, res, next) => {
  res.setHeader(
    'Content-Security-Policy',
    "default-src 'self'; script-src 'self' 'nonce-abc123'; style-src 'self' 'nonce-abc123'; report-uri /csp-report"
  );
  next();
});
Output
Browser enforces CSP; violations reported to /csp-report.
Try it live
🔥CSP is a powerful defense-in-depth
Even if an XSS vulnerability exists, CSP can prevent exploitation by blocking the malicious script.
📊 Production Insight
We deployed a CSP that blocked a third-party analytics script. We had to add the domain to the policy after verifying its security.
🎯 Key Takeaway
Implement CSP with nonces to block unauthorized scripts and styles.

Secure State Management and Data Exposure

React state management libraries like Redux or Zustand store data in memory. Never store sensitive data like passwords, tokens, or PII in the client state. If you must display sensitive data, fetch it on demand and clear it when the component unmounts. Be cautious with browser extensions that can access the DOM and state. Use Object.freeze on state objects to prevent mutation. For server-side rendering, avoid embedding secrets in the initial state. Use environment variables for configuration, but remember they are bundled into the client code — only use them for non-sensitive values.

store.jsJAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
// Avoid storing sensitive data
const initialState = {
  user: {
    id: null,
    name: null,
    // Never store: password, ssn, token
  }
};

// Use Object.freeze to prevent accidental mutation
const store = createStore(reducer, Object.freeze(initialState));
Output
State is immutable and contains no sensitive fields.
Try it live
⚠ Client state is not secure
Any data in the browser can be read by the user or malicious scripts. Keep sensitive data on the server.
📊 Production Insight
A developer stored a user's full address in Redux for convenience. A browser extension scraped it. We moved address display to server-rendered components.
🎯 Key Takeaway
Never store secrets in client state. Fetch sensitive data on demand and clear it.

Error Handling and Logging

Error handling is a security concern. Uncaught errors can leak stack traces, internal paths, and database schemas. Use error boundaries in React to catch rendering errors gracefully. Log errors on the server, not the client. Never display raw error messages to users. For API errors, return a generic message and log the details server-side. Use a centralized error tracking service like Sentry, but configure it to strip sensitive data. For development, use source maps but never deploy them to production.

ErrorBoundary.jsxJSX
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }
  static getDerivedStateFromError() {
    return { hasError: true };
  }
  componentDidCatch(error, info) {
    // Log to server, not console
    fetch('/api/log-error', {
      method: 'POST',
      body: JSON.stringify({ error: error.message }),
    });
  }
  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}
Output
Renders fallback UI and logs error server-side.
Try it live
💡Error boundaries are for UI, not security
They prevent the whole app from crashing, but you still need server-side logging to detect attacks.
📊 Production Insight
An uncaught error in a form component revealed the database table name in the console. We added an error boundary and server-side logging.
🎯 Key Takeaway
Catch errors gracefully, log server-side, and never expose internals to the client.

Security Testing and Auditing

Security is not a one-time effort. Integrate security testing into your CI/CD pipeline. Use static analysis tools like ESLint with security plugins (eslint-plugin-security, eslint-plugin-react-security). Run npm audit on every build. Use dynamic analysis tools like OWASP ZAP to scan for common vulnerabilities. Perform regular dependency audits with Snyk. For React-specific issues, check for missing key props, unsafe lifecycle methods, and improper use of refs. Penetration test your app before major releases. Keep a security checklist and review it during code reviews.

.eslintrc.jsonJSON
1
2
3
4
5
6
7
8
{
  "plugins": ["security", "react"],
  "rules": {
    "security/detect-object-injection": "error",
    "react/no-danger": "error",
    "react/no-unsafe": "error"
  }
}
Output
ESLint will flag dangerous patterns.
🔥Automate security checks
Manual reviews miss things. Use linters, dependency scanners, and SAST tools in CI.
📊 Production Insight
We added ESLint security rules and caught a dangerouslySetInnerHTML that slipped through code review. Now it's a build blocker.
🎯 Key Takeaway
Integrate security testing into CI/CD: linting, dependency audits, and dynamic scanning.

Production Hardening Checklist

Before deploying, run through this checklist: 1) All API endpoints require authentication. 2) CSP headers are set with nonces. 3) No secrets in client bundle. 4) Dependencies are audited and up-to-date. 5) Error boundaries are in place. 6) HTTPS is enforced. 7) Cookies are httpOnly, Secure, SameSite. 8) Input validation exists on both client and server. 9) Logging is configured without sensitive data. 10) Source maps are not deployed. 11) Rate limiting is enabled on API. 12) Third-party scripts are reviewed. Use tools like securityheaders.com to check your headers. Regularly review your threat model as your app evolves.

checklist.shBASH
1
2
3
4
5
6
# Run before deployment
npm audit --audit-level=high
npx eslint src/
npx snyk test
# Check CSP headers
curl -I https://yourapp.com | grep content-security-policy
Output
Audit passes, lint clean, CSP present.
💡Make security a release gate
Block deployments if any security check fails. Use CI to enforce it.
📊 Production Insight
We forgot to set CSP on a new microservice, and a reflected XSS was possible. Now we have a CI step that checks headers.
🎯 Key Takeaway
Use a production hardening checklist and automate security checks in CI.

Incident Response for React Apps

Even with the best defenses, incidents happen. Have a plan: 1) Detect: monitor logs and error reports for anomalies. 2) Contain: roll back the deployment, invalidate sessions, block malicious IPs. 3) Eradicate: patch the vulnerability, update dependencies. 4) Recover: restore from clean backup, redeploy. 5) Learn: conduct a post-mortem, update your threat model. For React apps, common incidents include XSS via a third-party script, leaked API keys in the bundle, or a compromised dependency. Practice incident response drills. Keep a runbook with steps for each scenario.

incident.jsJAVASCRIPT
1
2
3
4
5
6
7
8
9
// Example: Invalidate all sessions
async function invalidateAllSessions() {
  await fetch('/api/admin/invalidate-sessions', {
    method: 'POST',
    credentials: 'include'
  });
  // Clear client state
  window.location.href = '/login';
}
Output
All sessions invalidated; user redirected to login.
Try it live
⚠ Have a runbook ready
During an incident, you don't have time to figure out steps. Document them beforehand.
📊 Production Insight
We had a dependency compromised via a typo-squatting attack. Our runbook helped us roll back and patch within 30 minutes.
🎯 Key Takeaway
Prepare an incident response plan: detect, contain, eradicate, recover, learn.

Modern CSP: Nonce + strict-dynamic Pattern

Content Security Policy (CSP) is a critical defense against XSS attacks. For single-page applications (SPAs), the traditional whitelist-based CSP is often impractical due to dynamic script loading. The W3C-recommended approach uses nonces (cryptographic tokens) combined with the 'strict-dynamic' directive. This pattern allows only scripts with a valid nonce to execute, while 'strict-dynamic' automatically trusts scripts loaded by those approved scripts. This eliminates the need to maintain a whitelist of external domains. To implement, generate a unique nonce per request on the server and pass it to the React app. In your CSP header, use: script-src 'nonce-{random}' 'strict-dynamic' 'unsafe-inline' https:; object-src 'none'; base-uri 'none';. The 'unsafe-inline' is a fallback for older browsers; 'strict-dynamic' overrides it in modern ones. In React, add the nonce to script tags dynamically. For example, when loading a script: const script = document.createElement('script'); script.nonce = nonce; script.src = '...'; document.head.appendChild(script);. This pattern significantly reduces the attack surface by ensuring only server-approved scripts run.

cspNonceExample.jsJAVASCRIPT
1
2
3
4
5
6
7
8
9
10
// Server-side: generate nonce per request
const crypto = require('crypto');
const nonce = crypto.randomBytes(16).toString('base64');
res.setHeader('Content-Security-Policy', `script-src 'nonce-${nonce}' 'strict-dynamic' 'unsafe-inline' https:; object-src 'none'; base-uri 'none';`);

// Client-side: use nonce when dynamically adding scripts
const script = document.createElement('script');
script.nonce = nonce; // nonce passed from server (e.g., via meta tag or window.__NONCE__)
script.src = '/path/to/script.js';
document.head.appendChild(script);
Try it live
💡Why Nonce + strict-dynamic?
📊 Production Insight
In production, ensure nonces are generated per request and never reused. Use a middleware to inject the nonce into both the CSP header and the HTML response (e.g., via a meta tag or window variable).
🎯 Key Takeaway
Use nonce-based CSP with 'strict-dynamic' to secure React SPAs without relying on fragile whitelists.

CSP Report-Only Mode Deployment Strategy

Before enforcing a strict CSP, it's wise to test it using Report-Only mode. This mode sends violation reports without blocking resources, allowing you to identify and fix issues before going live. Set the header Content-Security-Policy-Report-Only instead of Content-Security-Policy. Configure a reporting endpoint using the report-uri or report-to directive. For example: Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report;. In React, you can set up a server endpoint to collect reports and log them. Use a monitoring service like Sentry or a custom logger. Analyze reports to find legitimate scripts that are being blocked and adjust your policy accordingly. Once confident, switch to enforce mode. This incremental approach prevents breaking your app in production. For SPAs, pay special attention to inline scripts and event handlers. Use the nonce pattern (see previous section) to allow necessary inline scripts. Report-Only mode is also useful for auditing third-party scripts and detecting potential XSS attempts.

cspReportOnly.jsJAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
// Server-side: set Report-Only header
res.setHeader('Content-Security-Policy-Report-Only', "default-src 'self'; script-src 'self'; report-uri /csp-report");

// Endpoint to collect reports (Express example)
app.post('/csp-report', (req, res) => {
  console.log('CSP Violation:', req.body);
  // Log to monitoring system
  res.status(204).end();
});

// In React, no changes needed; browser sends reports automatically
Try it live
🔥Gradual Rollout
📊 Production Insight
In production, set up a dedicated reporting endpoint with alerting. Regularly review reports to detect misconfigurations or attacks.
🎯 Key Takeaway
Use CSP Report-Only mode to safely test policies before enforcement, preventing production outages.
XSS Protection: React vs Raw HTML How React's default escaping compares to manual handling React JSX Raw HTML Injection Default Escaping Automatic via JSX Manual required Script Execution Blocked by default Possible if unsanitized dangerouslySetInnerHTML Opt-in with warning Common pattern User Input Rendering Safe with curly braces Vulnerable without escaping CSP Integration Easily combined Often overlooked THECODEFORGE.IO
thecodeforge.io
React Security

OWASP Top 10 for React Apps Mapping

The OWASP Top 10 is a standard awareness document for web application security. Mapping it to React helps prioritize risks. Here's a concise mapping:

  1. Broken Access Control: In React, ensure route guards (e.g., React Router) enforce authentication and authorization on the client, but always validate server-side.
  2. Cryptographic Failures: Use HTTPS; never store secrets in client-side code. Use environment variables for API keys.
  3. Injection: React's JSX auto-escapes, preventing XSS. However, dangerouslySetInnerHTML bypasses this. Avoid it or sanitize input.
  4. Insecure Design: Implement secure defaults, like using HttpOnly cookies for session tokens.
  5. Security Misconfiguration: Disable React DevTools in production, remove console logs, and use strict CSP.
  6. Vulnerable Components: Regularly update dependencies and use tools like npm audit.
  7. Authentication Failures: Use secure session management; avoid storing tokens in localStorage (use HttpOnly cookies).
  8. Data Integrity Failures: Validate data from APIs; use JSON Schema or TypeScript.
  9. Logging & Monitoring: Log security events (e.g., failed logins) but avoid logging sensitive data.
  10. SSRF: Avoid fetching user-supplied URLs without validation.

For each, React-specific mitigations exist. For example, to prevent injection, use React's built-in escaping and avoid eval(). For authentication, use libraries like Auth0 or Firebase with secure token storage.

owaspReactExample.jsJAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Example: Secure component with OWASP mitigations
import React, { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';

function SecureComponent({ user }) {
  const navigate = useNavigate();

  useEffect(() => {
    // Broken Access Control: client-side guard
    if (!user || !user.role === 'admin') {
      navigate('/login');
    }
  }, [user, navigate]);

  // Injection: avoid dangerouslySetInnerHTML
  const safeContent = { __html: '' }; // sanitized server-side

  return <div dangerouslySetInnerHTML={safeContent} />; // only if sanitized
}
⚠ Client-Side Only Is Not Enough
📊 Production Insight
Integrate OWASP checks into your CI/CD pipeline using tools like ESLint plugins or security scanners.
🎯 Key Takeaway
Map OWASP Top 10 to React-specific practices to systematically address common vulnerabilities.
⚙ Quick Reference
15 commands from this guide
FileCommand / CodePurpose
ThreatModel.jsxconst userComment = "";The Threat Model for React Apps
validation.tsconst CommentSchema = z.object({Input Validation and Sanitization
auth.jsres.cookie('session', token, {Secure Authentication and Session Management
SafeLink.jsxfunction SafeLink({ url, children }) {Protecting Against XSS in React
package.json{Dependency Management and Supply Chain Security
api.jsasync function fetchData(url) {Secure API Communication
csp.jsapp.use((req, res, next) => {Content Security Policy (CSP)
store.jsconst initialState = {Secure State Management and Data Exposure
ErrorBoundary.jsxclass ErrorBoundary extends React.Component {Error Handling and Logging
.eslintrc.json{Security Testing and Auditing
checklist.shnpm audit --audit-level=highProduction Hardening Checklist
incident.jsasync function invalidateAllSessions() {Incident Response for React Apps
cspNonceExample.jsconst crypto = require('crypto');Modern CSP
cspReportOnly.jsres.setHeader('Content-Security-Policy-Report-Only', "default-src 'self'; script...CSP Report-Only Mode Deployment Strategy
owaspReactExample.jsfunction SecureComponent({ user }) {OWASP Top 10 for React Apps Mapping

Key takeaways

1
Threat Modeling
Understand XSS, injection, and dependency risks before writing code.
2
Defense in Depth
Use React's escaping, CSP, input validation, and secure cookies together.
3
Never Trust the Client
Validate on the server, use httpOnly cookies, and avoid storing secrets in the bundle.
4
Automate Security
Integrate linting, dependency audits, and header checks into CI/CD.

Common mistakes to avoid

3 patterns
×

Not understanding React component re-rendering

Fix
Use React.memo, useMemo, and useCallback strategically to prevent unnecessary re-renders.
×

Ignoring the rules of hooks

Fix
Always call hooks at the top level, not inside conditions, loops, or callbacks.
×

Mutating state directly instead of using setState

Fix
Always use the state setter function and treat state as immutable.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
What is the Virtual DOM and how does React use it?
Q02JUNIOR
Explain the difference between state and props.
Q03JUNIOR
What is the purpose of the useEffect hook?
Q04JUNIOR
How does React handle keys in lists?
Q01 of 04JUNIOR

What is the Virtual DOM and how does React use it?

ANSWER
The Virtual DOM is a lightweight JavaScript representation of the real DOM. React diffs the Virtual DOM with the previous version and applies only the changed parts to the real DOM.
FAQ · 6 QUESTIONS

Frequently Asked Questions

01
Is React inherently secure against XSS?
02
Should I store JWTs in localStorage or cookies?
03
How do I protect against dependency vulnerabilities?
04
What is CSP and why should I use it?
05
How do I handle sensitive data in React state?
06
What should I do if I discover an XSS vulnerability in production?
N
Naren Founder & Principal Engineer

20+ years shipping production JavaScript and front-end systems at scale. Notes here come from systems that actually shipped.

Follow
Verified
production tested
July 13, 2026
last updated
2,018
articles · all by Naren
🔥

That's React. Mark it forged?

6 min read · try the examples if you haven't

Previous
React 19 New Features
11 / 40 · React
Next
React Lifecycle Methods (Legacy)