LabHub

Blog

Frontend Security 2025 — XSS, CSRF, CSP, Trusted Types, JWT, OAuth, PKCE, Passkeys, Supply Chain, SRI (S6 E9)

한국어English日本語

Prologue — the browser became a runtime, and attackers noticed

Frontend security used to mean "sanitize user input and set secure cookies." In 2026 the threat surface is an entire runtime: service workers, extensions, third-party scripts, bundled dependencies, and your own source. A frontend engineer without a security baseline ships vulnerabilities.

This post is the practical playbook: the threats that actually matter, the defenses that actually work, and the minimum every team should have.


1. The 2026 threat model

The OWASP Top 10 didn't change much. What changed is where the risks live:


2. XSS — Cross-Site Scripting

Three types:

Mitigations (layered)

  1. Framework output encoding — React, Vue, Svelte escape by default. dangerouslySetInnerHTML, v-html, {@html} are the exit hatches.
  2. Sanitizer API (2024 baseline) — browser-native sanitization: element.setHTML(untrustedHtml).
  3. DOMPurify — still the fallback for older browsers.
  4. CSP v3 with strict-dynamic — even if XSS lands, scripts can't execute without nonce/hash.
  5. Trusted Types — TS-like runtime check that innerHTML = x requires a TrustedHTML object.

CSP starter (2026)

Content-Security-Policy:
  default-src 'self';
  script-src 'nonce-{nonce}' 'strict-dynamic';
  style-src 'self' 'nonce-{nonce}';
  img-src 'self' data: https:;
  connect-src 'self' https://api.example.com;
  frame-ancestors 'none';
  base-uri 'none';
  object-src 'none';
  require-trusted-types-for 'script';
  trusted-types default dompurify;

strict-dynamic means "trust scripts with this nonce, and scripts they load" — removes the whitelist management nightmare.


3. CSRF — Cross-Site Request Forgery

For cookie-authenticated APIs, CSRF is still a risk.

Mitigations

For token-based APIs (JWT in Authorization header), CSRF doesn't apply — but XSS exfil does.


4. Authentication — OAuth, PKCE, Passkeys

OAuth 2.0 + PKCE

SPAs and mobile apps must use PKCE (Proof Key for Code Exchange). Implicit flow is deprecated.

Client/authorize?code_challenge=S256(random)
IdP → redirects back with code
Client/token with code + code_verifier

Tokens

Passkeys (WebAuthn)

2024 was the passkey breakthrough — Apple, Google, Microsoft all cross-synced. For new apps, passkey-first, password-fallback is now the modern default.


5. Cookies and sessions


6. JWT pitfalls

JWT is fine when used correctly — but common mistakes:

  1. Using JWT where sessions would do. If you can't revoke a JWT until it expires, you have a security problem.
  2. Storing JWT in localStorage — XSS steals it. Use httpOnly cookies.
  3. Weak secrets — HS256 with short secret is cracked in minutes. Use asymmetric (RS256/ES256) with rotation.
  4. Not validating aud and iss — easy to mix tokens between services.
  5. alg: none — ancient library bug, still worth checking.

7. Third-party scripts and supply chain

Every <script src=...> is a trust relationship. 2024 attacks (polyfill.io, node-ipc earlier) showed the risk.

Mitigations


8. CORS — the most-misunderstood header

CORS isn't security. It's a browser policy that protects users from malicious pages making authenticated requests to third-party APIs. Server still validates every request.

Rules


9. Click-jacking and framing


10. Headers cheat sheet (2026)

Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Content-Security-Policy: (see section 2)
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), geolocation=(), microphone=()
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Resource-Policy: same-site

Tools: securityheaders.com, Mozilla Observatory, browser DevTools Security panel.


11. Common leaks

  1. API keys in client bundles. NEXT_PUBLIC_* is exposed — never put secrets there.
  2. Source maps in production with full source — consider hidden-source-map with uploads to Sentry only.
  3. Console logs with PII — strip in production.
  4. Error messages leaking stack traces — sanitize for users, full for logs.
  5. Cache-control on authenticated pages — use Cache-Control: private or no-store.
  6. localStorage for sensitive data — XSS steal. Use sessionStorage at most, httpOnly cookies preferred.
  7. URLs with tokens — leak into Referer headers, analytics, logs.

12. Security in the AI era

  1. Prompt injection in LLM apps — treat user content before LLM as untrusted input. Sanitize prompts, separate system and user.
  2. Tool use access — if the LLM can call tools, restrict what it can do (allowlist).
  3. AI coding assistants leaking secrets.env in context = leak risk.
  4. Hallucinated packages — LLMs sometimes recommend non-existent npm packages, which attackers then register.

13. The minimum every team needs

  1. CSP v3 with nonces on HTML pages (not just unsafe-inline).
  2. Secure, HttpOnly, SameSite on session cookies.
  3. HSTS preload.
  4. Subresource Integrity on all third-party scripts.
  5. Dependabot/Renovate + audit workflow.
  6. No secrets in client bundles.
  7. CORS configured explicitly (not *).
  8. Regular dependency audit (npm audit, Snyk).
  9. Error tracking (Sentry) — so you see attacks early.
  10. Security review on any auth change.

12-item checklist

  1. CSP v3 with strict-dynamic and nonces?
  2. HSTS preload enabled?
  3. SRI on every third-party script?
  4. Passkey option available for auth?
  5. Short-lived access tokens + refresh rotation?
  6. XSS-resistant framework defaults used (no dangerouslySetInnerHTML)?
  7. SameSite=Lax (or Strict) on auth cookies?
  8. Source maps protected in production?
  9. Dependency audit automated?
  10. Security headers tool returns A+?
  11. Error tracking captures CSP violations?
  12. Secrets management audited (no NEXT_PUBLIC_ leakage)?

10 anti-patterns

  1. dangerouslySetInnerHTML with user content.
  2. JWT in localStorage.
  3. Access-Control-Allow-Origin: * with credentials.
  4. Ignoring CSP violation reports.
  5. Re-using JWT secrets across environments.
  6. Deploying source maps with full source.
  7. Passing auth tokens in URL query strings.
  8. Logging JWTs or cookies in client code.
  9. Bundling random CDN scripts without SRI.
  10. Rolling your own crypto (or JWT implementation).

Next episode

Season 6 Episode 10: State Management Renaissance 2025 — Zustand, Jotai, Valtio, TanStack Query, Signals, XState, RSC. Which state lives where in a 2026 React app.

— End of Frontend Security.

Comments

No comments yet.

Sign in to leave a comment