Frontend Security
XSS, CSRF, CORS, and where to put a token — the four things people get wrong.
Questions
Easy / Med / Hard
Your accuracy
Browser security has a specific shape: the attacker's code runs in your user's session, with your user's cookies.
XSS is code execution in your origin. Stored XSS is persisted and served to everyone; reflected comes back from the request; DOM-based never reaches the server at all, because a client-side sink like innerHTML executes attacker input directly.
Modern frameworks escape by default — React escapes any string rendered as a child — so almost all XSS in a React codebase enters through a deliberate bypass: dangerouslySetInnerHTML, a javascript: URL in an href, or injecting into a script context. If you must render user HTML, sanitise it with a maintained library rather than a regular expression.
Content Security Policy is the second line. It tells the browser which sources may execute, so an injection that gets through has nothing to run. It only works if you avoid unsafe-inline — a policy containing it permits precisely the attack it was meant to stop. Use nonces or hashes, and roll it out in report-only mode first.
CSRF only exists because cookies are sent automatically. An attacker's page submits a request to your site and the browser attaches the session cookie. SameSite=Lax is the modern default and blocks the cross-site cases that matter; Strict is stronger and breaks inbound links; anti-forgery tokens remain the belt-and-braces answer. If you authenticate with an Authorization header instead, CSRF largely disappears — nothing attaches that automatically.
CORS protects users, not your server. It is enforced by the browser, and only for browser-initiated cross-origin requests. It does not stop curl, a script, or anything without an origin to enforce. Loosening CORS does not expose your API; failing to authorise requests does. The corollary: never treat a passing CORS check as an authorisation check.
Where to store a token. localStorage is readable by any script in your origin, so a single XSS exfiltrates it. An httpOnly cookie is invisible to JavaScript but sent automatically, so it needs SameSite and Secure. The prevailing answer is an httpOnly, Secure, SameSite cookie holding a short-lived token — you trade an XSS problem for a CSRF problem that has a well-understood fix.
Clickjacking is your page framed invisibly over an attacker's. frame-ancestors in CSP is the current control.