Nuxt Fullstack Security Review
Purpose
Review Nuxt 3/4 full-stack code — nuxt.config.ts, composables/, plugins/,
server/api/, server/routes/, server/middleware/, and templates using
useState/v-html — for five defect classes Nuxt's own documentation and its
long-lived Nitro server model make security-critical: (a) private secrets placed
under runtimeConfig.public (or fed by NUXT_PUBLIC_* env vars) so they ship in the
client bundle, (b) useState/module-scope reactive or mutable state leaking across
requests in Nitro's single long-lived process, (c) server-route SSRF via
$fetch/ofetch to a user-controlled URL and blind forwarding of
useRequestHeaders()/credentials, (d) NuxtPayload/useState data reaching an
unsanitized render sink (XSS), and (e) missing security response headers
(routeRules headers, the nuxt-security module, useResponseHeader). This
skill exists so the review stays anchored to these five documented, structural
defect classes instead of drifting into a general "Nuxt code review."
When to use
Use this skill when the user asks to:
- review a Nuxt
nuxt.config.tsruntimeConfig/routeRulesblock for secret-exposure or missing-header risk, - review a
server/api/*orserver/routes/*handler that calls out to another service ($fetch/ofetch/event.$fetch), - investigate a report of one user seeing another user's data from a Nuxt app — the classic cross-request state pollution symptom,
- assess whether a
useState/payload value rendered withv-htmlis safe, - perform a pre-launch security review of a Nuxt 3/4 full-stack application.
Do not use this skill for:
- a Nuxt app's client-only component architecture, composable-extraction quality, or
reactivity-boundary design with no security angle — use
vue-composition-api-architecture-reviewinstead, - general Vue SSR concerns (non-Nuxt
entry-server.js, raw@vue/server-rendererusage) with no Nuxt-specific API involved — usevue-ssr-security-reviewinstead, - Vuex/Pinia store internals or Vue Router navigation-guard security with no
Nuxt-specific
runtimeConfig/server//useStatesurface — usevue-state-store-security-revieworvue-router-navigation-security-reviewinstead, - a bug that requires live traffic reproduction (concurrent-request load testing, a captured cross-user response, an actual SSRF probe against a running deployment) to confirm exploitation — static analysis proves the structural risk, not that it has already been exploited in production.
Context7 Documentation Protocol
- Resolve and query
/websites/nuxt_4_x(primary; Nuxt 4 prose docs) and/websites/nuxt_3_x(Nuxt 3 prose docs) before citing anyruntimeConfig,useState,$fetch/event.$fetch/useRequestFetch/useRequestHeaders, payload/devalue,routeRules, oruseResponseHeaderbehavior as fact. Both are Nuxt's own documentation site content mirrored into Context7 — treat matches from either asdocumentation-based. - Confirm which Nuxt major the target repo uses (
package.json'snuxtdependency) before assuming version-specific defaults; the APIs this skill covers are stable across 3/4, but state which major was confirmed when citing a claim. - The third-party
nuxt-securitymodule's exact default header set and configuration surface is not covered by Nuxt's own Context7-indexed docs — never state a specific default for it asdocumentation-based. Confirm its presence/config by reading the repo'snuxt.config.tsdirectly, and label any claim about its behaviorinferenceunless corroborated by the module's own documentation (not currently in scope for this skill's Context7 grounding). - Do not invent API names. If Context7 does not confirm an API or default, say so
explicitly and label the claim
inference. - If Context7 is unavailable, fall back to the
official_docsURLs in this skill'smetadata.jsonand label the claimdocumentation-based, unverified against current release.
Lean operating rules
- Every finding in this skill's five defect classes defaults to HIGH severity
(missing-security-headers may be MEDIUM-to-HIGH depending on the app's actual
surface — see
references/ssrf-payload-and-response-headers.md, Part 3). Do not downgrade a structuralruntimeConfigexposure, cross-request state leak, SSRF path, or payload-XSS trace to informational because it has not been observed exploited yet. - Trace every finding to a concrete file:line and a concrete data-flow path. A finding that says "this might leak the secret" or "this fetch call could be SSRF" without showing the specific config key, the specific module-scope declaration and its reachability, or the specific origin-to-sink trace is a guess, not a finding.
- Classify every
runtimeConfigkey by its actual nesting (top-level = private, underpublic= client-exposed) — never by variable name alone. A key namedapiSecretsitting insidepublicis exposed; a key namedbaseUrlsitting outsidepublicis still private and not itself a finding. - Classify every module-scope declaration on two axes before flagging it:
mutability/reactivity (only
useState/ref/reactive/mutable objects are at risk; immutable constants are not), and reachability from server-rendered code (a declaration no server-rendered path ever touches is not a finding in this scope). - Do not clear a
$fetch/ofetch/event.$fetchcall in a server route as safe from SSRF just because it "looks like an API call" — trace the destination URL to its origin and confirm either a hardcoded host or an explicit allowlist check before the request fires. - Do not clear a header-forwarding call (
event.$fetch's default forwarding,useRequestHeaders(...), or manual header spreading) as safe just because Nuxt documents the mechanism — the mechanism existing is not the same as its use being scoped to only the headers actually needed and only trusted destinations. - Do not approve a
useState/payload value reaching av-htmlbinding unless a named sanitizer call is visibly present on that exact traced path — a sanitizer existing elsewhere in the codebase does not clear this bar. - Do not report "no security headers" as cleared just because a mechanism
exists somewhere in the config — confirm the
routeRulesglob (or module config) actually covers the routes in scope before crediting it. - Never execute, build, or run application code, and never send live requests, as part of this review; this is a static-review skill (Read/Grep/Glob only).
- Load only the reference needed for the concern in scope.
References
Load these only when needed:
- Review workflow and findings contract — use for the step-by-step review procedure, the full decision tree across all five defect classes, and the required output shape.
- runtimeConfig exposure and cross-request state pollution
— load when reviewing
nuxt.config.ts'sruntimeConfigblock,NUXT_PUBLIC_*env vars, oruseState/module-scope reactive/mutable declarations reachable from server-rendered code. - Server-route SSRF, header forwarding, payload XSS, and missing response headers
— load when reviewing a
server/api/server/routeshandler's outbound$fetch/ofetch/event.$fetch/useRequestFetchcalls, auseState/payload value that renders somewhere, orrouteRules/security-module configuration. - Acceptance rubric — the authoritative list of defects this skill must catch and the false positives it must not raise; consult when unsure whether a pattern is in scope.
Response minimum
Return, at minimum:
- the
runtimeConfig/routeRulesblocks, module-scope declarations, server routes, and/or template bindings in scope, - ranked findings with file:line evidence, defect category
(
runtimeconfig-exposure/cross-request-state-pollution/ssrf/credential-forwarding/payload-xss/missing-security-headers), the concrete data-flow trace, and a fix sketch matching Nuxt's documented pattern, - for every
useState/payload → render-sink finding, an explicit statement of whether a sanitizer call is present on the traced path — never approve on the assumption one exists elsewhere, - evidence level per finding (
repo evidence,documentation-based, orinference), with structural risk findings explicitly labeled as structural risk, not as confirmed-exploited, - verdict (approve / approve-with-notes / block),
- open questions or scope the review could not cover (e.g., "confirming actual cross-request leakage requires concurrent-request load testing, not static review").