July 26, 2026
Web Security for Frontend Engineers — Part 1: The Overview
A field guide to shipping security without breaking the experience.

By Ayush Verma
7 min read
For a long time, security was something that happened somewhere else — the backend team's job, the InfoSec ticket, the checklist waved through two days before release.
That mental model is broken. Here's why it matters for us:
- Most attacks start where the user is — in the browser.
- They start in a URL someone was tricked into clicking, a form on a lookalike site, a token sitting in
localStorage, or a script from a CDN that quietly changed overnight. - The frontend isn't the soft underbelly behind the real defenses. It's the front door.
So this series treats frontend security as a first-class concern — as important as anything on the server, because the two are inseparable. This first part is the map. The rest go deep.
One rule sits above all the others:
Security should never come at the cost of the experience._ If your "secure" flow makes people want to bypass it, you haven't secured anything — you've just moved the vulnerability somewhere you can't see. Good security is mostly invisible. That's the bar._
The one mental model: never trust the client
If you remember nothing else, remember this:
- Everything in the browser is under the user's control — and therefore under an attacker's control.
- HTML can be edited. JS can be paused, patched, and replayed. Requests can be intercepted and rewritten.
- A disabled button is a suggestion, not a lock.
This kills the single most common misconception I see in reviews and interviews:
❌ Myth: "The user is authenticated, so we can trust what they send."
Not true:
- Authentication tells you who someone is.
- It says nothing about what they're allowed to do, or whether this specific request is legitimate.
- A logged-in seller is still a stranger to your
updateOrderendpoint — they can tamper with an ID to touch another seller's order, or have their session hijacked via XSS.
Bottom line: every meaningful control lives on the server. The frontend's job is to shrink the attack surface and not hand over the keys — not to be the last line of defense.
The roadmap
Fourteen topics, in the order we'll tackle them. Read this as a table of contents you can already reason about.
1. Cross-Site Scripting (XSS)
- What it is: the attacker gets their code to run inside your page.
- Sources (untrusted input): URL parameters, form fields, anything reflected back to the screen.
- Sinks (danger zones):
innerHTML,dangerouslySetInnerHTML,document.write,eval, ajavascript:URL in anhref.
// Safe: JSX escapes string children automatically.
<p>{userComment}</p>
// Dangerous: you just opted out of that protection.
<div dangerouslySetInnerHTML={{ __html: userComment }} />// Safe: JSX escapes string children automatically.
<p>{userComment}</p>
// Dangerous: you just opted out of that protection.
<div dangerouslySetInnerHTML={{ __html: userComment }} />- Defend with: encode on output, avoid the sinks, sanitize rich HTML (DOMPurify), and — the big one — a Content Security Policy so injected scripts have nowhere to run.
2. Iframe protection (clickjacking)
- What it is: your real site loaded in a transparent
<iframe>over a decoy. - The risk: the victim thinks they're clicking "Play video" but are actually clicking "Approve payout" on your page underneath.
- Defend with: refuse to be framed.
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none'X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none'frame-ancestors is the modern, flexible control; keep X-Frame-Options for older browsers.
3. Security headers
The cheapest, highest-leverage defenses you have — instructions the browser enforces for you:
Content-Security-Policy: default-src 'self'; script-src 'self'
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-originContent-Security-Policy: default-src 'self'; script-src 'self'
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-originContent-Security-Policy— restricts where scripts, styles, and connections load from (your strongest anti-XSS lever).X-Content-Type-Options: nosniff— stops the browser guessing content types.Referrer-Policy— controls how much of your URL leaks to other sites.
4. Client-side security
Where frontend engineers make the most expensive mistakes. So, bluntly:
- Anything in
localStorage/sessionStorageis readable by any JS on the page — including injected JS. One XSS bug and your token walks out the door. - Keep long-lived tokens out of Web Storage. Prefer an
HttpOnly,Secure,SameSitecookie the browser attaches automatically and JS can't read. - Use short-lived access tokens with real expiry, and refresh deliberately.
- Never dump PII, secrets, or full user objects into the browser for convenience — it's convenient for the attacker too.
Set-Cookie: session=...; HttpOnly; Secure; SameSite=StrictSet-Cookie: session=...; HttpOnly; Secure; SameSite=StrictIt's not "cookies good, storage bad." It's a trade-off: Web Storage → XSS token theft; cookies → CSRF (topic 14). Pick your poison and defend against it on purpose.
5. Secure communications (HTTPS)
- What it is: TLS encrypts traffic in transit so nobody on the network path — public Wi-Fi, a rogue router, an ISP — can read or tamper with it.
- Lock it in: tell the browser to never fall back to plain HTTP.
Strict-Transport-Security: max-age=63072000; includeSubDomains; preloadStrict-Transport-Security: max-age=63072000; includeSubDomains; preload- Why it's the foundation: without it, every other defense is theater — an attacker can rewrite your "secure" page as it travels.
6. Dependency security
- The reality: your app is mostly other people's code — that's the risk.
- The threats: typo-squatted packages, compromised maintainers, poisoned transitive dependencies running in your build and your users' browsers.
- Defend with: lockfiles, pinned versions, SCA tooling (BlackDuck, Fortify, Dependabot), and the habit of actually reading what you pull in.
7. Compliance & regulation
Not paperwork you bolt on at the end — it shapes architecture:
- Minimize the personal data you collect.
- Encrypt it at rest.
- Never store sensitive fields (PAN, bank details, full card numbers) in plaintext or in the browser.
- Frameworks to know: GDPR, India's DPDP Act, PCI-DSS.
"Can I put PII in Web Storage?" → a flat no, with a reason: it's readable by any script and lives outside your server's control.
8. Input validation & sanitization
Two different jobs people constantly confuse:
- Validation (on the way in): is this the right shape, type, and range? Client-side validation is a UX nicety for instant feedback — not security, because the client can be bypassed. The real check is on the server.
- Sanitization / encoding (on the way out): neutralize anything that could be read as code before rendering.
- Free win: React's JSX auto-escaping is sanitization you get for free — until you reach for
dangerouslySetInnerHTMLand opt out.
9. Server-Side Request Forgery (SSRF)
- What it is: you let a user influence a URL your server fetches, and they point it somewhere internal — a cloud metadata endpoint, an internal admin service.
- Whose problem: backend-flavored, but if you own a BFF (Backend-for-Frontend), it's yours.
- Defend with: allowlists, blocking internal address ranges, and never handing a raw user-supplied URL to your server's fetch.
10. Server-Side JavaScript Injection (SSJI)
- What it is: untrusted input reaches something that executes or interprets it on the server.
- Examples: an
evalon user input, or NoSQL operator injection like{ "password": { "$gt": "" } }sliding past a naive Mongo query. - Defend with: never evaluating user input, casting and validating types, and sanitizing query operators.
11. Permissions-Policy (formerly Feature-Policy)
- What it is: a header declaring which powerful browser features your page — and any iframes it embeds — are even allowed to use (camera, mic, geolocation, and more).
- Why it helps: turning off what you don't need shrinks the attack surface and limits what a compromised third-party frame can reach for.
Permissions-Policy: geolocation=(), camera=(), microphone=()Permissions-Policy: geolocation=(), camera=(), microphone=()12. Subresource Integrity (SRI)
- What it is: pin the hash of a CDN-hosted script so the browser refuses a file that's been swapped out from under you.
- The payoff: if the CDN is compromised and the file changes, the hash won't match and the browser won't run it. Cheap insurance against a supply-chain swap.
<script src="https://cdn.example.com/lib.js"
integrity="sha384-…"
crossorigin="anonymous"></script><script src="https://cdn.example.com/lib.js"
integrity="sha384-…"
crossorigin="anonymous"></script>13. CORS
Kill the myth first:
❌ Myth: "CORS protects my server."
- It protects your users' browsers, not your server.
- Same-Origin Policy stops a page on
evil.comfrom reading the response of a request it makes toyour-api.comusing the victim's cookies. - CORS is how your server selectively relaxes that rule for origins you trust.
- A
curlcall or any backend-to-backend request ignores CORS entirely — there's no browser to enforce it. - So: CORS is user-protection in the browser, never a substitute for real authorization on the server.
14. Cross-Site Request Forgery (CSRF)
- What it is: the mirror image of XSS — the attacker doesn't steal your session, they ride it.
- How it works: you're logged in; you open a malicious email or auto-submitting form, and your browser fires an authenticated request you never intended ("50% off!" quietly POSTs a password change).
- Defend with:
SameSitecookies, anti-CSRF tokens, and never mutating state on aGET.
_Keep the cousins straight: _XSS steals the session; CSRF abuses it.
The interview lens
Where these show up in senior frontend and EM interviews. Speak clearly to these six and you're ahead of most candidates:
- CORS — what it protects and what it doesn't.
- PII — how you handle it, what's sensitive, and why it never touches Web Storage.
- Validation vs sanitization — the difference, and where each belongs.
- Client-side storage & tokens — the XSS-vs-CSRF trade-off, and why long-lived tokens don't belong in
localStorage. - Authorization — the button-hiding trap, and enforcing on every request.
- XSS & CSRF — one crisp sentence each, one defense each.
The pattern behind all six: never trust the client, and know exactly which layer each defense lives on.
The golden rules
If this whole article collapsed into a sticky note:
- Never trust the client. Authentication is not authorization, and neither is trust.
- Validate on the server; sanitize on output. Client checks are UX, not security.
- Keep long-lived tokens out of Web Storage. Prefer
HttpOnlycookies; always use expiry. - Never store PII or secrets in the browser.
- Turn on the free wins: HTTPS, HSTS, a real CSP,
frame-ancestors,X-Content-Type-Options,Permissions-Policy. - Understand CORS as browser protection for your users — not a firewall for your server.
- Pin what you don't control: SRI on CDN scripts, locked and scanned dependencies.
- Never let security break the experience — a defense people route around isn't a defense.
What's next
That's the map. From here, each part takes one topic and goes deep — the attacks, real code, and the defenses I actually ship on a platform serving a lot of sellers and a lot of data.
Next up → Part 2: Cross-Site Scripting (XSS). From "what's a sink" to a production-grade defense, CSP included.
If a specific topic on this map is what keeps you up at night, tell me in the comments — I'll prioritize it.
Found this useful? Follow along for the rest of the series, and reach out if you're prepping for senior frontend or EM interviews.