When a Nuxt dev server is bound to a network-reachable interface (for example nuxt dev –host for on-device testing), the default-enabled Chrome DevTools workspace endpoint GET /.well-known/appspecific/com.chrome.devtools.json returns the absolute project root (workspace.root, i.e. rootDir) and a persistent per-project workspace UUID. GHSA-rq7w-g337-39qq added a gate (isLocalDevRequest) intended to restrict this endpoint to local requests, but that gate is header-based: it trusts request metadata rather than the connected peer address. A …
Nuxt server islands accept props via the /__nuxt_island/ endpoint. When an application has a server island component that forwards props directly into Vue's dynamic component resolution (<component :is>, resolveDynamicComponent, or h()), an attacker can pass a plain string value (rather than a component definition) to instantiate any globally-registered Vue component or any native HTML element. For example: { "as": "SomeGlobalComponent" } …resolves and renders SomeGlobalComponent if it is globally registered, …
An unauthenticated attacker can crash a Nuxt server that renders any island / server component containing a v-for over a prop (for example v-for="n in count" or a <slot v-for>). Because the island URL hash is a non-secret digest of the request, the attacker can compute a valid hash for arbitrary props and send the iterated prop as a large integer. The server then expands the v-for to that many …
The internal island renderer endpoint (/__nuxt_island/…) decodes and hashes attacker-controlled request input before it validates the URL-resident hash. An unauthenticated POST /__nuxt_island/<name>_<anything>.json with a large JSON body (for example ~4.6 MB / 150k keys) is fully read, destr-parsed, and run through ohash before the request is rejected with a 400. Because Nitro runs on a single event loop, this both wastes CPU on the doomed request and delays every concurrent …
Nuxt server islands accept props via the /__nuxt_island/ endpoint. When vue.runtimeCompiler: true is enabled (off by default) and the application has a server island component that forwards props into Vue's dynamic component resolution (<component :is>, resolveDynamicComponent, or h()), an attacker can inject a template key into the island props to achieve server-side remote code execution in the Nitro process. { "as": { "template": "<attacker-controlled>" } } Vue's runtime template compiler …
When a page is covered by routeRules cache / swr / isr, Nuxt enables runtime payload extraction and serves /<page>/_payload.json. On affected versions the renderer stored the SSR payload in the shared cache:nuxt:payload storage under a path-only key (no cookie, authorization, or cache.varies dimension) and, on a later payload request, returned the cached entry before route middleware / page guards ran again. As a result, once any authenticated user warms …
Nuxt matches route rules case-insensitively by default (mirroring vue-router's default sensitive: false routing). The fix for GHSA-mm7m-92g8-7m47 / CVE-2026-53721 lowercased the lookup path before matching route rules, but the route-rule keys compiled into the matcher were left verbatim. As a result, any route rule whose key contains an uppercase character (for example /Admin, /Dashboard/**, or the rules Nuxt derives from PascalCase/camelCase page files such as pages/Admin.vue) never matches, because every …
Three weaknesses in Nuxt's client-navigation URL handling, all reachable from documented public APIs (navigateTo and reloadNuxtApp): SSR open redirect in navigateTo via path-normalisation bypass. navigateTo decided whether a target was external by inspecting the raw input with hasProtocol(…, { acceptRelative: true }). Inputs such as /..//evil.com, /.//evil.com, /%2e%2e//evil.com, or /app/..//evil.com slipped past that check because they start with /, but WHATWG URL parsing then normalised them to the protocol-relative pathname …
Nuxt looks up routeRules for the current navigation by calling getRouteRules({ path: to.path }) from the page-router plugin and the no-pages router plugin. The compiled routeRules matcher (built on rou3) performs case-sensitive matching, while vue-router is configured with its default sensitive: false and matches paths case-insensitively. The two routers therefore disagree on which rules apply to a given request path: vue-router still matches the page record for /Admin/dashboard, but the …
<NuxtLink> did not validate the URL scheme of values bound to its to or href props before rendering them into the href attribute of the underlying <a> element. When an application binds attacker-controlled input (a query parameter, a CMS field, a user-supplied profile URL) to <NuxtLink :to> or :href, the attacker can supply a javascript: or vbscript: URL that is reflected verbatim into the rendered markup. Clicking the link executes …
When running nuxt dev on Linux (Node.js 20+, outside Docker / StackBlitz), Nuxt's internal vite-node IPC server binds to a Linux abstract-namespace Unix socket (\0nuxt-vite-node-<pid>-<ts>.sock). Abstract sockets have no filesystem inode and therefore no permission bits: any local UID on the host that can read /proc/net/unix can enumerate the socket and connect to it. The IPC server does not perform any peer-credential or shared-secret check before dispatching requests. The module …
Nuxt's globally registered <NoScript> component (from @unhead/vue head components, re-exported by Nuxt) wrote its default-slot content to the innerHTML of the <noscript> head tag, bypassing the HTML escaping that {{ }} interpolation normally applies in Vue templates. Applications that placed untrusted, attacker-controllable data inside a <NoScript> slot, for example: <NoScript>{{ route.query.banner }}</NoScript> would emit that value unescaped inside <noscript> in the server-rendered HTML. With scripting enabled, the HTML parser treats …
When running nuxt dev, Nuxt registers an unauthenticated route at /.well-known/appspecific/com.chrome.devtools.json that returns the absolute filesystem path of the project root and a per-project UUID persisted to node_modules/.cache/nuxt/chrome-workspace.json. The route is enabled by default via experimental.chromeDevtoolsProjectSettings: true. The endpoint exists to let Chrome DevTools' Workspace integration map sources to the developer's local checkout. The handler is registered directly on nitro.options.devHandlers and does not pass through the CORS / origin wrapper …
When experimental.componentIslands is enabled (default in Nuxt 4), any .server.vue file under pages/ is automatically registered as a server island under the key page_<routeName> and exposed via the /__nuxt_island/:name endpoint. Until this fix, requests through that endpoint rendered the page component directly via the SSR renderer without instantiating Vue Router, which meant route middleware declared on the page (including definePageMeta({ middleware })) did not run. For Nuxt applications that gate …
navigateTo() with external: true generates a server-side HTML redirect body containing a <meta http-equiv="refresh"> tag. The destination URL is only sanitized by replacing " with %22, leaving <, >, &, and ' unencoded. An attacker who can influence the URL passed to navigateTo(url, { external: true }) can break out of the content="…" attribute and inject arbitrary HTML/JavaScript that executes under the application's origin. This is a different root cause …
The /__nuxt_island/* endpoint accepts attacker-controlled props query/body parameters and renders any island component without verifying that the URL-resident hash (<Name>_<hashId>.json) was actually issued for those inputs by <NuxtIsland>. The hash is computed and embedded client-side but never validated server-side, so the same path can return materially different responses depending on the query. Island components are documented as rendering independently of route context - page middleware does not apply to them, …