
Frontend web security interview questions test whether you can reason about browser boundaries. You should be able to explain where untrusted data enters, where it is rendered, which cookies are sent automatically, which origins can read responses, and which checks must happen on the server.
The best answers are scenario-based. A definition of XSS, CSRF, or CORS is only the first step. Interviewers want to know what you would inspect, what you would change, what tradeoff you would accept, and how you would verify that the fix works.
For technical accuracy, use official references as your source of truth: the OWASP Top 10 for broad application risk, the OWASP XSS Prevention Cheat Sheet, the OWASP CSRF Prevention Cheat Sheet, MDN Web Security, MDN CORS, MDN CSP, MDN Set-Cookie, and MDN postMessage. Interview-question lists are useful for prompts; official docs are better for the actual answer.
Most frontend security answers become clearer if you first name the boundary. Do not start with "make it secure." Start with what the browser, frontend, API, or server is allowed to trust.
| Boundary | Interviewer is testing | Good answer should include |
|---|---|---|
| User content to DOM | XSS, output context, safe sinks | Source, sink, execution context, escaping, sanitization when rich HTML is allowed |
| Other site to your API | CSRF, cookies, request side effects | Automatic cookie sending, server-side token or origin validation, no side effects on GET |
| Other origin to your frontend | CORS, same-origin policy | Scheme/host/port origin, preflight, credential rules, CORS is not auth |
| Browser storage to attacker script | Token theft, session handling | XSS risk, cookie attributes, refresh flow, short lifetimes, server enforcement |
| Third-party code to your page | Supply-chain and script risk | Data access, CSP, route scoping, SRI where possible, dependency review |
| UI permission to API permission | Authorization boundary | Frontend UX checks versus server-side enforcement, 401 and 403 behavior |
XSS happens when untrusted data is interpreted as executable code in a page. In frontend interviews, connect the answer to the exact rendering path: where the data came from, which DOM sink receives it, and which parsing context the browser uses.
A good answer:
innerHTML when the content should be text.Common mistake: saying React, Vue, or Angular makes XSS impossible. Framework escaping helps with text rendering, but unsafe HTML APIs, unsafe URL handling, third-party scripts, and server-rendered templates can still create XSS risk.
React escapes text by default, but React does not remove every XSS path. XSS can still happen through dangerouslySetInnerHTML, untrusted markdown or HTML renderers, direct DOM manipulation through refs, dangerous URL schemes passed to DOM APIs, third-party scripts, and HTML created outside React.
Interview-ready answer:
"I would first check whether the value is rendered as text or HTML. If it is plain text, React's escaping is usually the right path. If the product needs rich text, I would sanitize with an allowlist, validate link protocols, avoid dangerous DOM sinks, and add tests for stored payloads. I would also check CSP and any third-party scripts on that page."
Validation checks whether input has the expected shape. Encoding changes output so the browser treats it as data in the current context. Sanitization removes or rewrites unsafe parts of content that is intentionally allowed to contain markup.
Example:
https:// or an allowed app route.Common mistake: saying "sanitize all input" as a universal answer. For plain text, the safer answer is usually to render it as text. Sanitization is for cases where the product intentionally allows rich content.
A safe sink treats data as text or a controlled value instead of executable markup. Examples include textContent, form value, and framework text interpolation when used normally.
The caveat matters: a sink is safe only for the right context. Hardcoded safe attribute names are different from dynamically choosing an attribute name. A URL attribute is different from normal text. An interviewer will often follow up with innerHTML, href, markdown, or rich-text examples to check whether the answer survives detail.
CSRF tricks a logged-in browser into sending a state-changing request that includes the user's cookies. The attacker may not be able to read the response, but the server may still receive and process the request.
Defenses include:
SameSite cookies as defense-in-depth.Origin or Referer checks for sensitive state-changing requests.GET.Common mistake: thinking HttpOnly prevents CSRF. HttpOnly prevents JavaScript from reading a cookie; it does not stop the browser from automatically sending that cookie.
HttpOnly, Secure, and SameSite protect?Cookie attributes reduce different risks, so name the risk instead of calling a cookie "secure."
| Attribute | Browser behavior | Does not protect against |
|---|---|---|
HttpOnly | Prevents JavaScript from reading the cookie through document.cookie | Requests caused by injected script or automatic cookie sending |
Secure | Sends the cookie only over secure connections, except for defined localhost handling | XSS, CSRF, or broken authorization |
SameSite=Lax or Strict | Restricts when the cookie accompanies cross-site requests | Every CSRF case or same-site attacks |
SameSite=None; Secure | Allows cross-site cookie use while requiring secure transport | CSRF, misconfigured CORS, or missing authorization |
Also mention that cookie Path is not an access-control boundary. It controls when the browser sends a cookie; it should not be treated as protection from unauthorized reading.
CORS is a browser-enforced mechanism that controls whether frontend JavaScript from one origin may read a response from another origin. An origin is the scheme, host, and port.
Good answer:
OPTIONS request.Access-Control-Allow-Origin: *.Common mistake: debugging React code when the actual problem is the API's CORS headers. If a request works in Postman but fails in the browser, check browser security rules before rewriting components.
There is no universal answer. The right storage choice depends on the auth model, threat model, and product constraints.
| Option | Useful when | Main risk |
|---|---|---|
| HttpOnly Secure cookie | You want to reduce token theft by JavaScript | Needs CSRF defenses for cookie-auth flows |
| Memory | You want less persistence after refresh or XSS cleanup | Harder refresh flow and tab coordination |
sessionStorage | You need tab-scoped persistence | Readable by injected scripts in that tab |
localStorage | Simpler persistence for bearer-token apps | Readable by injected scripts and often overused for long-lived tokens |
An interview-ready answer names the tradeoff: cookies reduce JavaScript token theft but require CSRF thinking; browser storage can simplify bearer-token flows but makes XSS theft more damaging. Short lifetimes, rotation, least privilege, refresh strategy, and server-side revocation matter more than declaring one storage location always safe.
CSP lets a site restrict which resources a page can load and which scripts can execute. It can reduce XSS impact by blocking inline scripts, javascript: URLs, unexpected script sources, and dangerous APIs such as eval() when the policy is strict enough.
A good answer:
unsafe-inline unless there is a temporary migration reason.Content-Security-Policy-Report-Only before enforcing a risky policy.Common mistake: adding a loose policy with unsafe-inline and many wildcard sources, then treating the page as protected.
postMessage be used safely?window.postMessage lets a window communicate with another window it references, such as a popup, parent, or iframe, even across origins. Workers and MessagePort objects have related messaging APIs, but targetOrigin and event.origin checks here apply specifically to window-to-window messaging.
Use a specific targetOrigin when sending. On receive, validate event.origin, check event.source when you expect one particular window, validate the message shape, and avoid sending secrets through generic message channels. If the message changes auth state, payment state, or account data, treat the receiver like any other trusted integration and document the expected source, origin, and schema.
Common mistake: using * for sensitive messages or trusting every message event because it arrived in the browser.
Frontend checks are useful for UX and accidental misuse, but they are not authorization. The frontend can hide irrelevant actions, disable impossible actions, validate form shape, and show useful auth recovery states. The server must enforce permissions and input validation for every sensitive operation.
Good answer:
401 as unauthenticated and 403 as authenticated but not allowed.Clickjacking tricks a user into interacting with a page framed by another site. The modern answer is to control who can embed the page, usually with the CSP frame-ancestors directive. Older systems may still use X-Frame-Options.
When your app embeds other content, review iframe sandbox permissions, allowed origins, postMessage contracts, and whether sensitive pages can be framed at all.
Common mistake: talking only about CORS. CORS controls browser script access to responses; it does not decide whether another site can frame your page.
Frontend code often runs with access to page content, user interactions, tokens in browser storage, and API responses. A third-party script, tag manager, or compromised dependency can therefore expand the damage from a single bug.
Good answer:
No real secret should be shipped to the browser. Anything in JavaScript bundles, source maps, HTML, network requests, local storage, or devtools-visible config should be treated as public.
Public API keys can be acceptable when the provider expects browser use and enforces restrictions server-side, such as allowed origins, scopes, quotas, and abuse controls. Private API keys, signing secrets, database credentials, and service-role tokens belong on the server.
For OAuth in SPAs, mention PKCE. PKCE improves public-client authorization flows, but it does not turn a browser into a place where client secrets can be hidden.
Service workers can intercept requests, cache responses, and keep behavior active beyond the current page. Review their scope, update strategy, cached sensitive data, logout behavior, and whether an old worker can serve stale authenticated content.
A good answer separates caching bugs from authorization bugs. Clearing UI state on logout is not enough if a service worker can still return sensitive cached responses.
Definitions help, but scenarios show judgment. Practice these as two-minute spoken answers.
| Scenario | What a good answer should reason through |
|---|---|
| User profile bio supports rich text | Plain text versus rich text, allowlist sanitizer, URL protocol validation, safe render path, stored XSS tests, CSP backup |
| Banking transfer uses cookie auth | CSRF token or equivalent server validation, SameSite, Origin/Referer checks, re-auth for high-risk action, no side effects on GET |
Dashboard calls api.example.com from app.example.com | Exact allowed origin, credential mode, preflight behavior, server auth, non-browser client caveat, 401/403 UI |
| Product wants a tag manager on every page | Data exposure, page scoping, CSP impact, consent rules, performance cost, incident response if the script is compromised |
| Admin button is hidden for normal users | UI convenience, server authorization, direct API test, 403 handling, audit logging |
| SPA uses bearer tokens | Storage tradeoff, XSS impact, refresh token flow, rotation, logout, multi-tab behavior |
| Comment preview renders markdown | Sanitized output, unsafe URLs, markdown library defaults, stored payload tests, final DOM inspection |
| App embeds a payment iframe | iframe origin, sandbox permissions, postMessage schema, no wildcard target for sensitive messages |
"Users can write comments with links, bold text, and lists. How would you prevent XSS?"
Start by asking whether the product needs plain text, markdown, or HTML. If plain text is enough, render it as text and avoid HTML. If rich text is required, define an allowlist of tags and attributes, sanitize on a trusted processing path, validate URL protocols, and avoid dangerous DOM sinks in the client.
Then verify the final DOM, not only the stored string. Test stored payloads, reflected payloads, image error handlers, unsafe links, malformed HTML, and post-sanitization mutations. CSP should reduce impact if something slips through, but it is not the primary fix.
Interview-ready answer:
"React escaping handles plain text, but rich text changes the problem. I would keep the allowed formatting small, sanitize with an allowlist, validate links so
javascript:cannot become anhref, render through a controlled component, and test stored comments in the rendered DOM. I would also check which third-party scripts run on the page because they change the impact of an XSS bug."
"The frontend at
https://app.example.comcallshttps://api.example.com/mewith cookies. It works in Postman but fails in the browser."
Postman is not enforcing browser CORS rules. The server must return CORS headers that allow the exact frontend origin. If credentials are included, the frontend request must use the right credential mode, and the server cannot rely on a wildcard origin for a credentialed response.
The API still needs authentication and authorization. CORS decides whether browser JavaScript may read the response; it does not prove that the user is allowed to access /me.
Interview-ready answer:
"I would check the browser console and network panel first. If credentials are involved, I would verify the request credential mode, the exact
Access-Control-Allow-Origin,Access-Control-Allow-Credentials, the preflight response, and the cookie attributes. After that, I would still check the API auth path because CORS is not authorization."
"The UI hides the Delete user button for non-admins. Is that enough?"
No. Hiding the button reduces accidental clicks and keeps the UI cleaner, but it does not enforce permission. A user can call the API directly, replay a request, use another client, or inspect the network request from an admin session.
The server should verify authorization for the delete action. The frontend should handle 403 deliberately, avoid leaking sensitive details, and keep the UI state consistent after a denied request.
Interview-ready answer:
"The frontend should hide the button for UX, but the API must enforce the permission. I would test by calling the endpoint directly as a non-admin and expecting
403. The UI should show a clear not-allowed state and not reveal extra data about the target user."
| Level | What the answer should show |
|---|---|
| Fresher | Can define XSS, CSRF, CORS, cookies, and why frontend validation is not authorization |
| Mid-level | Can identify unsafe rendering paths, token-storage tradeoffs, credentialed CORS risks, and 401/403 UI states |
| Senior | Can design layered defenses, review third-party script risk, coordinate frontend/backend responsibilities, and choose verification steps |
| Staff/lead | Can turn repeated mistakes into platform defaults, CSP rollout plans, dependency policy, review checklists, observability, and incident playbooks |
| Weak answer | Why it falls short | Better direction |
|---|---|---|
| "Use HTTPS" | HTTPS protects transport, not DOM XSS or broken authorization | Name the attack and the matching control |
| "React prevents XSS" | React escapes text by default, but unsafe sinks still exist | Explain the source, sink, and rendering context |
| "Store JWT in localStorage because it is easy" | XSS can read it | Discuss storage tradeoffs, token lifetime, refresh flow, and CSRF if cookies are used |
| "Disable CORS" | CORS is a browser access-control mechanism, not a bug to bypass | Fix the server policy and credential model |
| "Hide the button" | UI hiding is not authorization | Enforce permission on the server and handle 403 in the UI |
| "Add CSP and we are safe" | CSP is defense-in-depth | Keep safe rendering and sanitization as the primary XSS controls |
| "Sanitize input" | Too vague and often wrong for plain text | Say whether you validate input, encode output, or sanitize allowed HTML |
| Topic | Questions worth practicing |
|---|---|
| XSS | What are reflected, stored, and DOM XSS? What are unsafe sinks? How do HTML, attribute, URL, CSS, and JavaScript contexts differ? |
| React and frameworks | Why does React escaping help? How can dangerouslySetInnerHTML become risky? How should untrusted markdown be rendered? |
| Sanitization | When do you encode versus sanitize? Why is an allowlist safer than blocking known bad strings? What can go wrong after sanitization? |
| CSRF | Why do cookies make CSRF possible? How do CSRF tokens, SameSite, Origin checks, and avoiding side effects on GET work together? |
| Cookies | What do HttpOnly, Secure, SameSite, expiration, prefixes, and cookie scope protect against? What do they not protect against? |
| CORS and origins | What is an origin? What triggers a preflight? What changes when credentials are included? Why does CORS not replace authorization? |
| Tokens | Should tokens live in cookies, memory, sessionStorage, or localStorage? How do refresh tokens change the risk? |
| CSP | What does CSP block? What are nonces and hashes? Why can unsafe-inline weaken a policy? How do report-only rollouts help? |
| Trusted Types | What problem does Trusted Types reduce? Which dangerous DOM APIs does it affect? Why is migration work needed? |
| Browser APIs | How do postMessage, iframes, service workers, Web Storage, clipboard APIs, and Web Workers create review points? |
| Frontend permissions | What should the UI hide, what should it disable, and what must the server enforce? How should 401 and 403 states differ? |
| Third-party code | How do analytics, tag managers, embeds, npm packages, and CDN scripts change the damage from a frontend bug? |
| Secrets | Which values can be public in a browser bundle? Which values must stay on the server? Why does PKCE not hide a client secret? |
| Testing | How do you review a PR for XSS risk? What payloads would you test? What belongs in automated tests versus manual review? |
| Incident thinking | If a script was compromised, what data could it read, what actions could it trigger, and what would you rotate or revoke? |
Practice by drawing the boundary first: browser, frontend code, API, cookie jar, third-party script, user-controlled input, storage, or server permission check.
For each answer, name the browser or server boundary and one verification step. For example, an XSS answer should end with a rendered-DOM test; an authorization answer should end with a direct API call using an unprivileged account.
Prepare for REST API interview questions as a frontend fresher with answers on HTTP methods, status codes, fetch, CORS, auth, caching, pagination, errors, and API contracts.
Discover fundamental HTML, CSS, and JavaScript knowledge with these expert-crafted interview questions and answers. Perfect for freshers preparing for junior developer roles.
Explore advanced JavaScript interview questions and answers designed for engineers with 5+ years of experience, curated by big tech senior engineers.
Explore advanced JavaScript interview questions and answers designed for engineers with 10+ years of experience, curated by big tech senior engineers.
Prepare for PayPal frontend interviews with real question patterns, React and JavaScript prep, payments system design, and a 2026 study plan.