A fullstack Nuxt developer owns both halves of the attack surface: the browser, where XSS, CSRF and leaked tokens live, and the Nitro server, where injection, SSRF and broken authorisation live. Interviewers rarely ask for exploits; they ask what you do by default, what you check in review, and what you would say to a product manager who wants to render user-provided HTML. This section is that default posture.
postMessage, and your own database when it holds user content. Every boundary needs validation on entry and encoding on exit.SameSite cookies (most CSRF), HttpOnly (XSS cannot read the session), CSP (limits what injected code can do), HTTPS with HSTS. What it does not give you: authorisation, input validation, protection from your own dependencies.runtimeConfig keeps secrets server-side; readValidatedBody validates inputs; nuxt-auth-utils seals sessions; production error pages hide stack traces. What they do not give you: safety in v-html, javascript: URLs, user templates, or any server route you forget to protect.| Page | Question it answers |
|---|---|
| XSS and output encoding | "Where can script injection happen in a Vue app, and how do you render user HTML safely?" |
| CSP and security headers | "Which headers do you ship, and how do you roll out a Content Security Policy in Nuxt?" |
| Auth, sessions and CSRF | "Sessions or JWT? How do you protect against CSRF? How do you authorise?" |
| Server-side risks | "Injection, SSRF, path traversal, uploads, secrets, errors: what do you check in a Nitro route?" |
| Supply chain and dependencies | "What did the 2025 npm attacks teach you, and how is your pipeline protected?" |
The security checklist applied to one Nitro route:
import { z } from 'zod'
import DOMPurify from 'isomorphic-dompurify'
const body = z.object({
postId: z.string().uuid(),
html: z.string().max(5_000), // bounded input: DoS via 50 MB comments is a validation problem
})
export default defineEventHandler(async (event) => {
const { user } = await requireUserSession(event) // authentication
const input = await readValidatedBody(event, body.parse) // validation at the boundary (400 on failure)
const post = await useDb().posts.find(input.postId)
if (!post || !post.allowsComments) throw createError({ status: 404, statusText: 'Not found' }) // object-level authorisation
await assertRateLimit(event, `comments:${user.id}`, { max: 10, windowSec: 60 }) // abuse control
const safe = DOMPurify.sanitize(input.html, { ALLOWED_TAGS: ['b', 'i', 'a', 'p', 'code'], ALLOWED_ATTR: ['href'] }) // encode/sanitise on the way in
const comment = await useDb().comments.create({ postId: post.id, authorId: user.id, html: safe })
log.info({ event: 'comment.created', userId: user.id, commentId: comment.id }) // audit trail, no content or PII
return comment
})
"Vue escapes output so we are safe from XSS" and "Nuxt is server-rendered so tokens are safe" are half-truths interviewers probe. Vue escapes interpolation, not v-html, href schemes or style bindings; Nuxt gives you the tools for sessions and validation but every route must use them. Name the mechanism, then the gap.
"In trust boundaries and defaults. Untrusted input enters from URLs, bodies, headers, cookies, uploads, third parties and my own database when it holds user content; each entry validates with a schema and each exit encodes for its context. The browser gives me the same-origin policy, SameSite and HttpOnly cookies, CSP and HTTPS, and I configure them deliberately; it does not give me authorisation or input validation, so every server route authenticates, checks the object it is about to touch, validates and bounds its input, and never leaks stack traces or secrets. Then I treat the process as part of the surface: dependencies updated on a cadence with a release delay, CI with least privilege, security releases applied fast, and logs that would let me notice an incident. The OWASP Top 10, including its 2025 additions on supply chain and error handling, is the checklist I review against."
Nothing yet. Notes filed here show up on every page of this section.
Web APIs worth knowing by name
The platform APIs a senior frontend engineer should be able to reach for without searching — URL and encoding, Web Crypto, files and blobs, history and the Navigation API, View Transitions, Page Lifecycle and bfcache, the Performance and observer APIs, Speculation Rules, clipboard and share, Web Components and WebAssembly — with the questions each one answers.
XSS and output encoding
The three kinds of cross-site scripting, exactly what Vue escapes and what it does not, the sinks to watch — v-html, href and src schemes, style bindings, user templates, JSON in script tags, SVG uploads, postMessage — sanitisation with DOMPurify on both sides, Trusted Types, and how CSP limits the blast radius.