System-design · Frontend Security

Frontend Security Interview Questions
With Answers & Code Examples

6 carefully curated Frontend Security interview questions with working code examples and real interview gotchas.

Practice Interactively →← All Categories
6 questions3 beginner2 core1 advanced
Q1Beginner

What is XSS (Cross-Site Scripting) and how do you prevent it?

💡 Hint: Attacker injects script that runs in another user's browser — prevent by escaping output, using CSP, and never using innerHTML with user data

XSS occurs when an attacker injects malicious JavaScript into a page that is then executed in another user's browser, giving the attacker access to cookies, tokens, and the DOM.

Three types:

  • Stored XSS — malicious script is saved in the database (e.g., a comment) and served to every user who views it.
  • Reflected XSS — script is embedded in a URL, reflected in the response (e.g., search results page).
  • DOM-based XSS — client-side JS reads attacker-controlled data (URL hash, postMessage) and writes it to the DOM unsafely.

Prevention:

  • Never use innerHTML, dangerouslySetInnerHTML, or document.write with untrusted data. React auto-escapes by default — this is why it's safer.
  • Output encoding — HTML-encode user content before rendering it.
  • Content Security Policy (CSP) — restricts which scripts can execute; blocks inline scripts.
  • Sanitize HTML input — if you must allow rich text, use DOMPurify.
import DOMPurify from 'dompurify';
// Safe: sanitize before dangerouslySetInnerHTML
const clean = DOMPurify.sanitize(userHtml);
<div dangerouslySetInnerHTML={{ __html: clean }} />
Practice this question →
Q2Beginner

What is CSRF and how do SameSite cookies and CSRF tokens prevent it?

💡 Hint: Forged cross-origin request that rides on the victim's cookies — SameSite blocks cookie sending; CSRF token requires secret the attacker doesn't have

CSRF (Cross-Site Request Forgery) tricks a logged-in user's browser into making an unintended request to a site where they're authenticated. The browser automatically sends cookies, so the server sees it as legitimate.

<!-- On attacker's site -->
<img src="https://bank.com/transfer?to=attacker&amount=1000" />
<!-- Browser auto-sends bank.com cookies with this request -->

Prevention 1: SameSite cookies

  • SameSite=Strict — cookie never sent on cross-origin requests. Breaks OAuth flows.
  • SameSite=Lax — cookie sent on top-level navigations (GET links) but not on embedded requests (img, form POST from other sites). Good default.
  • SameSite=None; Secure — sent everywhere (cross-origin). Requires HTTPS.

Prevention 2: CSRF tokens

// Server sets a CSRF token in a readable cookie (not HttpOnly) or in page HTML
// Client reads it and sends it as a header
const csrfToken = getCookieValue('csrf-token');
fetch('/api/transfer', {
  method: 'POST',
  headers: { 'X-CSRF-Token': csrfToken }, // attacker can't read this
});

Attackers can't read the CSRF token from a different origin (same-origin policy), so they can't forge the header.

Practice this question →
Q3Core

What is a Content Security Policy (CSP) and how does it work?

💡 Hint: HTTP header that whitelists sources for scripts, styles, images — blocks injected inline scripts and unknown CDNs

A Content Security Policy is an HTTP response header that tells the browser which sources are allowed to load scripts, styles, images, fonts, etc. Violations are blocked.

Content-Security-Policy:
  default-src 'self';
  script-src 'self' https://cdn.example.com;
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: https:;
  frame-ancestors 'none';

Key directives:

  • default-src — fallback for all resource types not explicitly listed.
  • script-src — which origins can serve JavaScript.
  • frame-ancestors — which origins can embed this page in an iframe (replaces X-Frame-Options).
  • 'nonce-{random}' — whitelist an inline script by including a per-request nonce: <script nonce="r4nd0m">.
  • 'strict-dynamic' — trust scripts loaded by trusted scripts (allows dynamic script injection from whitelisted scripts).

Reporting: Use Content-Security-Policy-Report-Only header to log violations without blocking — essential when rolling out a CSP to a production app.

💡 Aim for a CSP that eliminates 'unsafe-inline' for scripts. Nonces (Next.js middleware) are the practical way to achieve this with SSR apps.
Practice this question →
Q4Beginner

What is clickjacking and how do you prevent it?

💡 Hint: Attacker overlays your page in a transparent iframe — victim clicks on attacker UI but triggers your authenticated actions; prevent with frame-ancestors CSP

Clickjacking is an attack where a malicious page embeds your site in a transparent <iframe>. The victim sees the attacker's UI but their clicks land on your page's controls (like a "Transfer Funds" button).

Prevention methods:

1. Content-Security-Policy: frame-ancestors (preferred)

Content-Security-Policy: frame-ancestors 'none';
// or allow only same origin:
Content-Security-Policy: frame-ancestors 'self';

2. X-Frame-Options (legacy, still supported)

X-Frame-Options: DENY
X-Frame-Options: SAMEORIGIN

frame-ancestors in CSP supersedes X-Frame-Options and supports more granular control (e.g., allow specific partners).

3. Frame-busting JS (weak, not recommended)

if (window.top !== window.self) window.top.location = window.location;

Attackers can defeat this with sandbox attribute on the iframe. Always use HTTP headers instead.

Practice this question →
Q5Core

What security HTTP response headers should every production frontend set?

💡 Hint: X-Content-Type-Options, X-Frame-Options/CSP frame-ancestors, HSTS, Referrer-Policy, Permissions-Policy

A hardened production app should set these headers on every HTML response:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
# Forces HTTPS for 1 year; prevents SSL-stripping attacks

X-Content-Type-Options: nosniff
# Stops browser MIME-type sniffing — prevents treating a text/plain response as JavaScript

X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none'
# Prevents clickjacking

Referrer-Policy: strict-origin-when-cross-origin
# Limits how much URL info leaks in Referer header

Permissions-Policy: camera=(), microphone=(), geolocation=()
# Disables browser features your app doesn't use

Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{n}'; ...
# Restricts resource origins; mitigates XSS

Quick audit: Run your URL through securityheaders.com to get a score and missing header report.

In Next.js: Set these in next.config.js under headers() or in middleware for per-request nonces.

Practice this question →
Q6Advanced

How do you protect a frontend app against dependency supply chain attacks?

💡 Hint: Lock file, Subresource Integrity, audit CI, minimal dependencies, private registry proxying

Supply chain attacks target the npm packages your app depends on (e.g., the event-stream malware, left-pad removal, typosquatting).

Defenses:

1. Lock files — commit package-lock.json or pnpm-lock.yaml. CI runs npm ci (not npm install) to install exact locked versions.

2. Automated auditing — run npm audit or pnpm audit in CI; fail the build on high-severity CVEs. Dependabot or Renovate auto-opens PRs for patches.

3. Subresource Integrity (SRI) — for third-party CDN scripts, add a integrity hash. Browser refuses to execute the script if the hash doesn't match.

<script
  src="https://cdn.example.com/lib.js"
  integrity="sha384-abc123..."
  crossorigin="anonymous"></script>

4. Minimal dependency footprint — every added package is an attack surface. Prefer native browser APIs; audit new deps on Bundlephobia and Snyk before adding them.

5. Private registry proxy — proxy npm through Artifactory or Verdaccio; allows allow-listing, caching, and scanning before packages reach developers.

Practice this question →

Other System-design Interview Topics

Rendering Strategies →Core JS →Type System →React Fundamentals →Functions →Microfrontends →Generics →Async JS →Hooks →Objects →Monorepo →Arrays →'this' Keyword →Utility Types →Error Handling →Modern JS →Bundle Optimization →Performance →DOM & Events →State Management →Classes & OOP →Caching Strategies →Component Patterns →Advanced Types →Authentication →React Router →Forms →Advanced Patterns →Concurrent React →Server Components →Testing →Ecosystem →Network Optimization →Core Web Vitals →Browser APIs →

Ready to practice Frontend Security?

Get AI feedback on your answers, predict code output, and fix real bugs.

Start Free Practice →