Back to Blog
How-To 9 min read

SOC 2 Controls for React Frontends: What Auditors Look For

Learn which SOC 2 controls apply to React frontends — covering XSS prevention, authentication token handling, CSP headers, third-party script governance, and dependency scanning.

Key Takeaways
  • React auto-escapes JSX expressions, but auditors still check for unsafe HTML rendering patterns — audit your codebase and require DOMPurify for any dynamic HTML.
  • Store access tokens in memory (Zustand or React context), not localStorage, to prevent XSS-based token theft.
  • Implement a Content Security Policy header via your CDN or server to restrict script sources and prevent injected scripts from executing.
  • Run npm audit and Snyk in CI to catch vulnerable frontend dependencies before they reach production.
  • Govern third-party scripts with a vendor inventory and CSP hash allowlisting — rogue scripts are a common SOC 2 audit finding.

Does SOC 2 apply to the frontend?

SOC 2 auditors scope the entire system that processes or stores customer data — including the frontend. CC6 (logical access) applies to authentication flows, token handling, and session management. CC6.6 covers input validation. CC7 covers monitoring, which includes frontend error tracking.

Frontend-specific audit findings are less common than backend findings, but they do occur. The most frequent: access tokens stored in localStorage (visible to any XSS payload), missing Content Security Policy headers, and third-party analytics scripts loaded without a vendor review.

React's architecture is inherently XSS-resistant because JSX expressions are auto-escaped by the renderer. The main risks are React's unsafe HTML rendering prop (explicit opt-out of escaping), third-party scripts injected into the DOM, and prototype pollution from untrusted JSON.

XSS prevention in React

React auto-escapes JSX expressions, but audit your codebase for usage of the unsafe HTML rendering prop: `grep -r 'dangerousHTML' src/`. Any usage must sanitize the HTML with DOMPurify before rendering — pass the sanitized string to the __html property.

Add ESLint rules to prevent unsafe patterns: eslint-plugin-security and eslint-plugin-no-unsanitized catch the unsafe HTML rendering prop used without sanitization and other dangerous dynamic code execution patterns.

For rendering markdown or rich text from user input, use a sanitizing renderer (rehype-sanitize, DOMPurify) rather than raw HTML injection. Document approved rendering libraries in your secure coding standard.

Secure token storage patterns

Store access tokens in JavaScript memory — Zustand store, React context, or a module-level variable. Memory storage means the token is cleared on page refresh and tab close, and is inaccessible to XSS payloads that can only read DOM and storage APIs.

Use httpOnly, Secure, SameSite=Strict cookies for refresh tokens. The browser sends these cookies automatically with same-origin requests, and JavaScript cannot read them. Implement a silent refresh: on page load, call a /auth/refresh endpoint that reads the httpOnly cookie and returns a new access token into memory.

Never store access tokens in localStorage or sessionStorage. Both are accessible to any JavaScript running on the page. If an XSS payload executes, it can exfiltrate the token. This is a direct CC6.1 finding and one of the most common frontend audit failures.

Content Security Policy headers

A Content Security Policy (CSP) header instructs the browser to only execute scripts from approved sources. A strict React CSP: `Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{RANDOM}'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' https://api.yourapp.com`.

For nonce-based CSP with Next.js, generate a cryptographically random nonce per request in middleware and inject it into the CSP header and into script tags. This allows your bundle to execute while blocking injected scripts that lack the nonce.

Start with `Content-Security-Policy-Report-Only` to collect violations without breaking the app. Use a reporting endpoint (report-uri.com or your own endpoint) to collect violations for 2-4 weeks, then tighten the policy based on real traffic patterns.

Third-party script governance

Maintain a vendor inventory of every third-party script loaded by the frontend: analytics (Google Analytics, Segment), support widgets (Intercom, Drift), error tracking (Sentry), and A/B testing tools. Each vendor must have a completed vendor security questionnaire before the script is added.

Load third-party scripts with the `integrity` attribute (Subresource Integrity) when possible. SRI hashes ensure the browser rejects any script that has been tampered with in transit or at the CDN. Generate hashes with `openssl dgst -sha384 -binary script.js | openssl base64 -A`.

Include third-party script domains in your CSP `script-src` directive. Removing a vendor from the frontend should also trigger removal from the CSP and the vendor inventory. Review the vendor list quarterly as part of CC9 (vendor management).

Frontend dependency scanning

Run `npm audit --audit-level=high` in CI and fail the build on high or critical findings. For more detailed reporting, add Snyk (`snyk test`) with a project token. Both tools check transitive dependencies, not just direct ones.

Frontend dependency trees are large (often 1000+ packages). Prioritise vulnerabilities in packages that handle user input, cryptography, or HTTP requests. A CVE in a pure development dependency (like a test runner) is lower risk than one in a request parsing library.

Pin exact dependency versions with a lockfile (`package-lock.json` or `yarn.lock`) committed to git. Use Dependabot or Renovate for automated patch PRs. Configure Renovate to auto-merge patch updates for non-breaking changes and require review for minor/major bumps.

React SOC 2 checklist

Before your audit window: (1) Grep for unsafe HTML rendering prop usage — any found must use DOMPurify. (2) Access tokens stored in memory only, not localStorage. (3) httpOnly refresh token cookie with SameSite=Strict. (4) CSP header deployed with nonce or hash-based script allowlist. (5) Third-party vendor inventory current and reviewed. (6) npm audit or Snyk passes in CI with zero high/critical findings. (7) Frontend error monitoring (Sentry) configured with PII scrubbing.

Map each item to a Trust Service Criteria code for your evidence package: XSS prevention → CC6.6, token storage → CC6.1, CSP → CC6.6, vendor inventory → CC9.2, dependency scanning → CC7.1, error monitoring → CC7.2.

Frequently Asked Questions

Does SOC 2 require a bug bounty programme for the frontend?
No — a bug bounty is not required by SOC 2. However, some auditors view it as additional evidence of a mature vulnerability management programme. What is required is documented vulnerability disclosure procedures (how you receive and respond to externally reported vulnerabilities) and a defined SLA for remediation.
Is localStorage always prohibited for token storage?
For access tokens: yes, avoid localStorage. For non-sensitive user preferences (theme, locale), localStorage is fine. The prohibition is specifically about authentication credentials and session tokens that would allow account takeover if exfiltrated.
Do CSP violations count as security incidents?
CSP violations in report-only mode are informational. Once you enforce a CSP, a violation means a script was blocked — which could indicate an attempted injection or a misconfigured legitimate resource. Route violations to your security monitoring pipeline and investigate spikes.
How does React Query / SWR affect SOC 2?
React Query and SWR are data-fetching libraries with no direct SOC 2 implications. Ensure that stale cache data cannot lead to privilege escalation — for example, if a user role changes, invalidate cached queries on session refresh. Log cache invalidation events as part of your audit trail where they relate to access control changes.
Does server-side rendering (Next.js) change the SOC 2 scope?
Yes — SSR moves rendering logic to a Node.js process, which is now in scope for server-side controls: secrets management, dependency scanning, logging, and input validation all apply to the SSR layer. Treat the Next.js server as a backend service and apply the same controls as your API layer.

Automate your compliance today

AuditPath runs 86+ automated checks across AWS, GitHub, Okta, and 14 more integrations. SOC 2 and DPDP Act. Free plan available.

Start for free