Skip to content

chore(deps): update devdependency nuxt to v4.4.7 [security]#302

Open
renovate[bot] wants to merge 1 commit into
mainfrom
renovate/npm-nuxt-vulnerability
Open

chore(deps): update devdependency nuxt to v4.4.7 [security]#302
renovate[bot] wants to merge 1 commit into
mainfrom
renovate/npm-nuxt-vulnerability

Conversation

@renovate

@renovate renovate Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor

ℹ️ Note

This PR body was truncated due to platform limits.

This PR contains the following updates:

Package Change Age Confidence
nuxt (source) 4.1.24.4.7 age confidence

nuxt vulnerable to Cross-site Scripting in navigateTo if used after SSR

CVE-2024-34343 / GHSA-vf6r-87q4-2vjf

More information

Details

Summary

The navigateTo function attempts to blockthe javascript: protocol, but does not correctly use API's provided by unjs/ufo. This library also contains parsing discrepancies.

Details

The function first tests to see if the specified URL has a protocol. This uses the unjs/ufo package for URL parsing. This function works effectively, and returns true for a javascript: protocol.

After this, the URL is parsed using the parseURL function. This function will refuse to parse poorly formatted URLs. Parsing javascript:alert(1) returns null/"" for all values.

Next, the protocol of the URL is then checked using the isScriptProtocol function. This function simply checks the input against a list of protocols, and does not perform any parsing.

The combination of refusing to parse poorly formatted URLs, and not performing additional parsing means that script checks fail as no protocol can be found. Even if a protocol was identified, whitespace is not stripped in the parseURL implementation, bypassing the isScriptProtocol checks.

Certain special protocols are identified at the top of parseURL. Inserting a newline or tab into this sequence will block the special protocol check, and bypass the latter checks.

PoC

POC - https://stackblitz.com/edit/nuxt-xss-navigateto?file=app.vue

Attempt payload X, then attempt payload Y.

Impact

XSS, access to cookies, make requests on user's behalf.

Recommendations

As always with these bugs, the URL constructor provided by the browser is always the safest method of parsing a URL.

Given the cross-platform requirements of nuxt/ufo a more appropriate solution is to make parsing consistent between functions, and to adapt parsing to be more consistent with the WHATWG URL specification.

Note

I've reported this vulnerability here as it is unclear if this is a bug in ufo or a misuse of the ufo library.

This ONLY has impact after SSR has occurred, the javascript: protocol within a location header does not trigger XSS.

Severity

  • CVSS Score: 5.1 / 10 (Medium)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Nuxt: Reflected XSS in navigateTo() external redirect

CVE-2026-45669 / GHSA-fx6j-w5w5-h468

More information

Details

Summary

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 from CVE-2024-34343 (GHSA-vf6r-87q4-2vjf), which addressed javascript: protocol bypass. The issue here is triggered by any valid URL containing >.

Impact

Applications that pass user-controlled input to navigateTo(url, { external: true }) — typically via a ?next= / ?redirect= query parameter used for post-login or "return to" flows — are vulnerable to reflected cross-site scripting. The injected script runs in the context of the application's origin during the server-rendered redirect response, before the meta-refresh fires.

Details

In packages/nuxt/src/app/composables/router.ts, the SSR redirect path builds an HTML response body with only " percent-encoded in the destination URL:

const encodedLoc = location.replace(/"/g, '%22')
nuxtApp.ssrContext!['~renderResponse'] = {
status: sanitizeStatusCode(options?.redirectCode || 302, 302),
body: `<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=${encodedLoc}"></head></html>`,
headers: { location: encodeURL(location, isExternalHost) },
}

The Location header is normalised through encodeURL() (which uses the URL constructor and correctly percent-encodes attribute-significant characters). The HTML body uses a narrower sanitiser. That mismatch is the root cause.

Proof of concept

Global middleware that forwards a query parameter to navigateTo:

// middleware/redirect.global.ts
export default defineNuxtRouteMiddleware((to) => {
const next = to.query.next as string | undefined
if (next) {
 return navigateTo(next, { external: true })
}
})

Request:

GET /?next=https://evil.example/x><img src=x onerror=alert(document.domain)>

Response body:

<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=https://evil.example/x><img src=x onerror=alert(document.domain)>"></head></html>

The > after evil.example/x terminates the content="…" attribute, and the <img onerror> tag executes JavaScript in the application's origin before any redirect
occurs.

Patches

Fixed in nuxt@4.4.6 and nuxt@3.21.6 by #​35052. The fix percent-encodes the full set of HTML-attribute-significant characters (&, ", ', <, >) before interpolating the URL into the meta-refresh body

Workarounds

If you can't upgrade immediately, validate user-controlled URLs before passing them to navigateTo(url, { external: true }). At minimum, normalise through new URL(input).toString() and reject inputs containing < or > (a normalised URL with these characters is malformed and safe to refuse).

Severity

  • CVSS Score: 5.3 / 10 (Medium)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Nuxt: __nuxt_island endpoint does not bind responses to request props, enabling shared-cache poisoning

CVE-2026-46342 / GHSA-g8wj-3cr3-6w7v

More information

Details

Summary

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, and they are intentionally cacheable as a function of their props. This advisory does not treat that contract as a vulnerability. It treats the absence of a binding between the URL the cache keys on and the response served at that URL as one.

Impact

In applications where a CDN or reverse-proxy in front of the app caches /__nuxt_island/* keyed by path only (ignoring query) - a documented misconfiguration class, see GHSA-jvhm-gjrh-3h93 - an attacker can prime the cache for a path with their own choice of props, and subsequent users requesting the same path receive the attacker's rendered HTML rather than the response intended for them. The cache entry persists until normal expiry.

Where the affected island has any prop flowing into an unsafe HTML sink in application code (v-html, innerHTML, a third-party renderer treating a prop as HTML), this becomes stored XSS in the embedding page's origin until the cache entry expires. HttpOnly cookies remain out of reach but anything else in the origin (other cookies, in-origin requests, DOM state) is reachable by the injected script.

Preconditions:

  • experimental.componentIslands enabled (or the default 'auto' with at least one server / island component in the app).
  • A shared intermediary cache (CDN, reverse-proxy, edge cache) keyed on path only.
  • For the XSS pivot specifically: an application-authored island that puts a prop through an unsafe HTML sink.

Without the second precondition, the response shape is per-request and unaffected. Without the third, the worst case is content-swap / inert HTML injection rather than script execution.

Patches

Patched in nuxt@4.4.6 and nuxt@3.21.6 by #​35077. The island handler now recomputes the expected hashId from (name, props, context) using the same ohash function <NuxtIsland> already uses to embed the hash in the URL, and rejects requests (HTTP 400) whose URL-resident hash does not match. The response is now a pure function of the request path: a path-keyed shared cache returns the correct response to every requester for that path, and an attacker cannot synthesise a path whose hash matches arbitrary props.

Workarounds

For users unable to upgrade immediately:

  • Ensure any intermediary cache keys /__nuxt_island/* on the full query string, not on the path alone. This is the recommended configuration regardless.
  • Audit application-authored islands for props flowing into v-html / innerHTML / similar HTML sinks; treat island props as untrusted user input.
Note on island authentication

[!IMPORTANT]
It's important to remember that route middleware does not run when rendering island components, and islands cannot rely on routing-layer auth. Applications gating sensitive data behind page middleware should enforce that auth inside the island's own data layer (server-only routes, useRequestEvent + manual session checks, etc.) rather than relying on the embedding page's middleware - this was true before this advisory and remains true after it.

A separate advisory addresses *.server.vue pages registered as page_<routeName> islands, where the documented "middleware doesn't run for islands" contract collides with the page's own definePageMeta({ middleware }) declaration in a way that constitutes a genuine bug rather than documented behaviour.

Severity

  • CVSS Score: 2.3 / 10 (Low)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Nuxt's route middleware is not enforced when rendering .server.vue pages via /__nuxt_island/page_*

CVE-2026-47200 / GHSA-hg3f-28rg-4jxj

More information

Details

Summary

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 a .server.vue page behind route middleware as their sole auth check, an unauthenticated attacker could bypass that check by requesting /__nuxt_island/page_<routeName>_<anyhash> directly and receiving the server-rendered HTML.

Affected configurations

All three conditions must hold for an application to be vulnerable:

  1. experimental.componentIslands is enabled (the default in Nuxt 4; opt-in in Nuxt 3).
  2. The application defines one or more .server.vue files under pages/, registering them as routed pages.
  3. Authentication / authorization for at least one such page is enforced solely via route middleware (middleware/*.ts referenced from definePageMeta), without a server-side check inside the page or its data layer.

Applications that enforce auth inside the island's own data layer (server-only API routes, useRequestEvent + manual session checks, etc.) were not affected. The general "route middleware does not run for non-page island components" behaviour is documented and unchanged; this advisory concerns the .server.vue page case specifically, where running middleware is the user's clear expectation.

Details
  • Build (packages/nuxt/src/components/templates.ts): .server.vue pages are registered as island components with page_ prefix, making them addressable through /__nuxt_island/page_<routeName>_<hashId>.
  • Runtime (packages/nitro-server/src/runtime/handlers/island.ts): the handler resolves the requested island component and renders it via renderer.renderToString(ssrContext). The Vue Router plugin previously short-circuited middleware execution whenever ssrContext.islandContext was set.
  • The two paths interact so that route middleware declared on the source page never runs.
Proof of concept

Given a page app/pages/secret.server.vue:

<script setup lang="ts">
definePageMeta({ middleware: 'auth' })
</script>

<template>
<h1>SECRET DATA</h1>
</template>

with middleware/auth.ts blocking unauthenticated access:

##### Direct page request: blocked by middleware
curl -i http://localhost:3000/secret

##### -> 403 / redirect, depending on the middleware

##### Island request: middleware did not run before this fix
curl -i 'http://localhost:3000/__nuxt_island/page_secret_anyhash'

##### -> 200 OK, body includes <h1>SECRET DATA</h1>
Patches

Patched in nuxt@4.4.6 and nuxt@3.21.6 by #​35092. The Vue Router plugin now runs middleware and redirect handling for page_* islands (i.e. islands that originate from .server.vue files in pages/). The island handler propagates middleware-issued responses (~renderResponse), and a new beforeResolve guard returns HTTP 400 when the requested page_<name> does not match the route component the URL resolves to.

Non-page island components are unaffected - they continue to render without route middleware, by design.

Workarounds

If you cannot upgrade immediately:

  • Enforce authentication inside the .server.vue page itself, not via route middleware. Read the session from useRequestEvent() and throw createError({ statusCode: 401 }) (or redirect) before returning data. This is the recommended pattern for islands regardless of this advisory.
  • Disable experimental.componentIslands if your app does not use the feature.
  • If your app must keep route-middleware-only auth, gate the /__nuxt_island/page_* URL prefix at your reverse proxy or in a server middleware.

Severity

  • CVSS Score: 6.3 / 10 (Medium)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Nuxt: Dev server discloses project absolute path and persistent workspace UUID via /.well-known/appspecific/com.chrome.devtools.json

GHSA-rq7w-g337-39qq

More information

Details

Summary

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 that the rest of the dev pipeline uses, so it has no host / origin / Sec-Fetch-Site check of its own.

Impact

Dev-server only. Production builds do not register the route.

Two values are disclosed:

  • workspace.root: the absolute filesystem path of the project (commonly reveals the OS username and the on-disk project name).
  • workspace.uuid: a v4 UUID persisted to node_modules/.cache/nuxt/chrome-workspace.json, stable across dev-server restarts and re-clones.
Threat model

The response carries no Access-Control-Allow-Origin header. A cross-origin fetch() from an arbitrary malicious page is therefore blocked by the browser's same-origin policy and cannot read the body. The two realistic recovery paths are:

  1. LAN-adjacent attacker when the developer runs nuxt dev --host (or otherwise binds to a non-loopback interface). A plain curl http://<dev-lan-ip>:3000/.well-known/appspecific/com.chrome.devtools.json returns the JSON; no browser, no CORS.
  2. DNS rebinding against the default loopback dev server. A page the developer visits resolves to the attacker, then re-resolves to 127.0.0.1 after the TTL; the browser believes the request is same-origin and reads the response.
Affected versions

nuxt@4.0.0-alpha.1 (PR #​32084) through nuxt@4.4.6. 3.x is not affected.

Reproduction
npx nuxt dev
curl -s http://localhost:3000/.well-known/appspecific/com.chrome.devtools.json

##### {"workspace":{"uuid":"...","root":"/Users/<name>/..."}}
Workaround

Set experimental: { chromeDevtoolsProjectSettings: false } in nuxt.config.ts. Chrome DevTools' Workspace auto-integration will stop working; the dev server is otherwise unaffected.

Patches

Fixed in nuxt@4.4.7 by #​35201 (commit 55c75b78). The handler is now routed through the same host / origin gate the rest of the dev server uses, so the endpoint only responds to requests that look local.

Severity

  • CVSS Score: 2.3 / 10 (Low)
  • Vector String: CVSS:4.0/AV:A/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Nuxt: URL-handling weaknesses in navigateTo and reloadNuxtApp: SSR open redirect, client-side script execution via the open option, and protocol-relative bypass in reloadNuxtApp

GHSA-c9cv-mq2m-ppp3

More information

Details

Summary

Three weaknesses in Nuxt's client-navigation URL handling, all reachable
from documented public APIs (navigateTo and reloadNuxtApp):

  1. 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 //evil.com. The normalised value was
    written to the Location response header and into the
    <meta http-equiv="refresh"> body of the SSR redirect page, so a
    victim's browser would resolve the redirect cross-origin to the
    attacker's host.

  2. Client-side script execution via navigateTo({ open: ... }). The
    client-side early-open handler called window.open(toPath, ...) without
    applying the isScriptProtocol check that gates the normal navigateTo
    path. A target of javascript:... (or another script-capable scheme)
    passed to navigateTo(url, { open: { ... } }) therefore executed in the
    application's origin instead of being rejected.

  3. Open redirect in reloadNuxtApp via protocol-relative bypass.
    reloadNuxtApp({ path }) rejects script-capable protocols by parsing
    the path with new URL(path, window.location.href) and checking the
    resolved protocol against isScriptProtocol. Protocol-relative paths
    such as //evil.com resolve to the current page's protocol (https:),
    which passes that check; the value is then assigned to
    window.location.href, which the browser treats as a cross-origin
    redirect. This is the same protocol-relative bypass family as (1), in
    a different sink.

Impact

For (1), the practical risk is phishing or OAuth-code theft against any
Nuxt app that forwards user-controlled input (for example a ?next=
query parameter on a login route) into navigateTo on the server. The
framework documents that navigateTo blocks external hosts unless
external: true is passed, so maintainers commonly rely on it as the
safe path for post-login redirects.

For (2), any app that passes a user-controlled URL into
navigateTo(url, { open: { ... } }) was vulnerable to reflected XSS in
the application's first-party origin.

For (3), any app that forwards user-controlled input into
reloadNuxtApp({ path }) could be redirected cross-origin for phishing
or OAuth-code theft, even on releases that already shipped the
isScriptProtocol guard added by #​35115.

Patches

Fixed in nuxt@4.4.7 and backported to nuxt@3.21.7. The three sinks
are addressed by:

Workarounds
  • For (1): validate redirect targets before passing them to navigateTo,
    for example reject any input where
    new URL(target, 'http://localhost').pathname starts with //, or
    only accept a known allow-list of paths.
  • For (2): reject any user-controlled URL whose protocol is not in an
    allow-list (typically just http: and https:) before passing it to
    navigateTo({ open: ... }).
  • For (3): same shape as (1). Reject paths starting with // (or where
    new URL(path, window.location.href).host !== window.location.host)
    before passing to reloadNuxtApp({ path }).
References
  • CWE-601: URL Redirection to Untrusted Site ('Open Redirect')
  • CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Credits

Reported by Anthropic / Claude as ANT-2026-S08HN6DH through Anthropic's
coordinated vulnerability disclosure programme.

The reloadNuxtApp protocol-relative bypass (sink 3) was independently
reported by @​alcls01111 via GitHub's
coordinated disclosure flow (GHSA-w7fp-2cfv-4837), closed as a
duplicate of this advisory.

Severity

  • CVSS Score: 5.1 / 10 (Medium)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:L/VI:L/VA:N/SC:N/SI:L/SA:N

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Nuxt: Route-rule middleware bypass via case-sensitivity mismatch between vue-router and the routeRules matcher

CVE-2026-53721 / GHSA-mm7m-92g8-7m47

More information

Details

Impact

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 routeRules lookup for the same path
returns no match. Any appMiddleware declared via routeRules is never
added to the middleware set and never runs, on both SSR and client
navigations. The same path skips other path-keyed route rules in the
same way (ssr, redirect, appLayout, and the prerender / payload
hints used client-side).

For applications using routeRules with appMiddleware as an
authorization gate (a documented pattern), an attacker can flip the case
of any static segment in a protected URL (for example /Admin/dashboard
instead of /admin/dashboard) to render the protected page with the
middleware skipped. The server returns the fully server-rendered page
including any useFetch / useAsyncData results captured during SSR.

This is an instance of CWE-178 (Improper Handling of Case Sensitivity)
leading to CWE-863 (Incorrect Authorization) for apps that treat
appMiddleware as an authorization boundary.

Mitigating factors
  • Only affects apps that use routeRules.appMiddleware. The more
    idiomatic definePageMeta({ middleware }) is bound to the matched
    route record and is unaffected.
  • Nuxt route middleware is documented as an app-layer concern, not a
    server-side auth boundary; well-built apps enforce authorization
    again at the API / data-fetching layer.
  • Apps that explicitly set router.options.sensitive = true are not
    affected.
Patches

Fixed in nuxt@4.4.7 (commit 07e39cd6) and backported to nuxt@3.21.7 (commit 3f3e3fa7). The fix normalizes the path used for routeRules lookups so it matches vue-router's default case-insensitive semantics.

Workarounds

Until you can upgrade, you can mitigate by either:

  1. Setting router.options.sensitive = true so vue-router matches
    case-sensitively (this changes route-matching behaviour app-wide).
  2. Moving security-critical middleware off routeRules.appMiddleware
    and onto definePageMeta({ middleware: [...] }) on the protected
    page components, which is bound to the matched record.
  3. Enforcing authorization at the API / data-fetching layer (which you
    should be doing in any case).
Credit

Reported by Anthropic / Claude through Anthropic's coordinated
vulnerability disclosure process. Reference: ANT-2026-9FSEBYMC.

Severity

  • CVSS Score: 8.8 / 10 (High)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:L/VA:N/SC:N/SI:N/SA:N

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Nuxt dev server vite-node IPC socket is world-connectable on Linux

GHSA-534h-c3cw-v3h9

More information

Details

Impact

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 request type passes its moduleId field straight into Vite's SSR fetchModule(), which is not gated by Vite's HTTP-layer server.fs.allow deny-list. A co-resident unprivileged local user can therefore request paths like /home/<dev>/project/.env?raw or ~/.ssh/id_rsa?raw and read the developer's secrets through the dev server's SSR plugin pipeline. The resolve request type additionally enables filesystem probing.

This affects developers running nuxt dev on shared multi-tenant Linux hosts (lab machines, shared bastions, CI runners shared between jobs without per-job container isolation). It does not affect:

  • Production builds (nuxt build / nuxt start). The IPC server only runs in development.
  • macOS or Windows developers.
  • Docker / StackBlitz environments, which already fall back to a filesystem socket.
  • Single-user laptops or per-job containerised CI.
Patches

Fixed in nuxt@4.4.7 (commit 1f9f4767) and backported to nuxt@3.21.7 (commit c293bf95).

The fix removes the abstract-namespace branch entirely. The IPC server now always binds to a filesystem Unix socket under the OS temp directory and explicitly chmod 0600s it after listen(), restricting connections to the owning UID. If the chmod fails for any reason, the server closes rather than serve requests on an unrestricted channel.

Workarounds

If you cannot upgrade immediately on an affected host:

  • Run nuxt dev inside a container or VM with no other tenants. Docker already triggers the filesystem-socket fallback in vulnerable versions and that fallback is unaffected.
  • Bind the dev process to a single-user namespace (unshare -U, rootless containers).
  • Restrict /proc/net/unix visibility via hidepid=2 mount options where applicable, though this is partial mitigation only.
References
  • Affected file: packages/vite/src/plugins/vite-node.ts
  • CWE-276: Incorrect Default Permissions
Credit

Reported by Anthropic / Claude as part of Anthropic's coordinated vulnerability disclosure programme, reference ANT-2026-MSNKZFAT. Thanks to the Anthropic security team for the report and the detailed reproduction.

Independently reported by @​alcls01111 via GitHub's coordinated disclosure flow (GHSA-5gvc-46gq-948j), closed as a duplicate of this advisory.

Severity

  • CVSS Score: 5.5 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Nuxt: Reflected XSS in <NuxtLink> via unsanitised javascript: or data: URL

CVE-2026-53722 / GHSA-934w-87qh-qr26

More information

Details

Summary

<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 the supplied script in the origin of the Nuxt application, resulting in reflected DOM-based cross-site scripting. A data:text/html,... payload reflected through the same sink does not execute in the application's origin but enables a same-tab phishing surface anchored to a legitimate application link.

The same value was exposed to consumers of the component's custom slot via the href and route.href props, so applications that re-bind those values to their own anchors were affected identically.

Unlike the previously reported navigateTo issue (CVE-2024-34343), the sink here is the rendered anchor itself; the existing isScriptProtocol checks in navigateTo and reloadNuxtApp are not on the code path. The onClick handler intentionally returns early for external links so the browser's native protocol-based navigation runs.

Affected component
  • File: packages/nuxt/src/app/components/nuxt-link.ts
  • Sink: h('a', { href: href.value, ... }) in the default render, plus the href / route.href props passed to the custom slot.
  • Broken check: external auto-detection treated any hasProtocol(path, { acceptRelative: true }) value as an "external link", then rendered the value directly as <a href> without rejecting script-capable protocols. There was no equivalent of the navigateTo isScriptProtocol(protocol) gate in this path.
Impact

Any Nuxt application that binds user-controlled values to <NuxtLink :to> / :href was vulnerable. Common shapes: profile-link rendering (<NuxtLink :to="user.website">), "share this" / "open in new tab" handlers that pass through a query parameter, CMS-driven landing pages that render <NuxtLink :to="cms.cta.url">, and marketplace listings that show seller-supplied links.

For javascript: / vbscript: the primitive is reflected XSS in the application's first-party origin (session theft for non-HttpOnly cookies, CSRF token theft, account takeover via DOM rewriting, credential harvesting via fake login overlays). For data:text/html,... the attacker gets a same-tab phishing surface anchored to a legitimate application link.

Patches

Fixed in nuxt@4.4.7 (commit 0103ce06) and backported to nuxt@3.21.7 (commit 53284043). The fix sanitises the resolved external href before it is passed to <a> or the custom slot: control characters and whitespace are stripped, leading view-source: prefixes are unwrapped, and any remaining script-capable scheme (per isScriptProtocol) causes the href to be replaced with an empty string.

Workarounds

Until you can upgrade, validate URLs at the source before binding them to <NuxtLink :to> / :href. For example, only accept paths that start with / (and not //), or run user-supplied URLs through new URL(value) and reject anything whose protocol is not in an allow-list (typically http: and https:).

Severity

  • CVSS Score: 5.1 / 10 (Medium)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Cross-site scripting via slot content in Nuxt's head components

GHSA-m3q2-p4fw-w38m

More information

Details

Impact

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 <noscript> content in <head> under the "in head noscript" insertion mode: any tag other than link, meta, noframes, or style implicitly closes <noscript> and is re-processed in the head. A payload such as <script>...</script> therefore escapes the element and executes in the document context.

Sibling head components (<Style>, <Title>) were not affected because they already routed slot text through the safe textContent path.

Affected versions

All currently supported versions of nuxt that ship the <NoScript> global component.

Patches

Fixed in nuxt@4.4.7 (commit 4b054e9d) and backported to nuxt@3.21.7 (commit 7fea9fd6). The fix escapes <NoScript> slot content with escapeHtml from @vue/shared and writes it to textContent rather than innerHTML. Slot content is now rendered as text; intentional markup inside <NoScript> is no longer parsed as HTML.

Workarounds

Until you can upgrade:

  • Do not interpolate untrusted input into <NoScript> slots. Replace <NoScript>{{ x }}</NoScript> with a static string, or sanitise / HTML-escape x at the source.
  • If you must render dynamic noscript content, write the tag yourself via useHead({ noscript: [{ textContent: escapedValue }] }) after escaping escapedValue.
Credit

Reported to Anthropic's coordinated vulnerability disclosure pipeline by Claude (Anthropic's AI assistant) and triaged by the Anthropic security team. Reference: ANT-2026-4NJYDFFM.

Independently reported by @​alcls01111 via GitHub's coordinated disclosure flow (GHSA-8grp-wcq9-925q), closed as a duplicate of this advisory.

Severity

  • CVSS Score: 2.3 / 10 (Low)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Release Notes

nuxt/nuxt (nuxt)

v4.4.7

Compare Source

4.4.7 is a security hotfix release.

👉 make sure to check https://github.com/nuxt/nuxt/security/advisories to view open advisories resolved by this release.

👉 Changelog

compare changes

🩹 Fixes
  • nitro: Assign noSSR before deciding payload extraction (#​35108)
  • vite: Avoid filtering out dirs with shared prefix from allowDirs (#​35112)
  • nuxt: Use resolve from pathe for buildCache path boundary check (#​35111)
  • nuxt: Prevent sibling-directory traversal in test component wrapper (#​35110)
  • nitro: Pass event data to isValid in dev clipboard-copy listener (#​35109)
  • nuxt: Validate protocols in reloadNuxtApp path before reload (#​35115)
  • vite: Prefix public asset virtuals with null byte (9e303b438)
  • nuxt: Re-run getCachedData after initial fetch (#​35122)
  • nuxt: Propagate useFetch/useAsyncData factory types (#​35133)
  • vite: Close vite dev server on nuxt close (a10a68abc)
  • kit,nuxt: Handle cancelling prompts to install packages (e84813229)
  • kit: Avoid excluding node-context files in legacy tsconfig (#​35152)
  • nuxt: Handle missing payload in chunkError listener (#​35155)
  • nuxt: Await in-lifght template generation when closing nuxt (#​35181)
  • nuxt: Clarify page and layout usage warnings (#​35184)
  • webpack: Surface compilation errors when stats.toString is empty (073b07851)
  • nuxt: Reject prototype-chain keys in the island registry (#​35205)
  • nuxt: Apply isScriptProtocol guard to navigateTo open option (#​35206)
  • nuxt: Prevent server-only page island from recursing via <NuxtPage> (#​35198)
  • rspack,webpack: Require loopback host when missing same-origin signals (#​35200)
  • nitro: Gate chrome devtools workspace endpoint to local requests (#​35201)
  • nuxt: Escape props in <NuxtClientFallback> ssr output (#​35199)
  • kit: Improve TS extension stripping/substitutions (#​35233)
  • nuxt: Preserve .d.mts/.d.cts in resolveTypePaths (#​35235)
  • nuxt: Escape <NoScript> slot content (4b054e9d9)
  • nuxt: Match route rules case-insensitively to mirror vue-router (07e39cd6f)
  • nuxt: Reject script-capable protocols in <NuxtLink> href (0103ce06f)
  • nuxt: Block path-normalization open redirect in navigateTo (2cce6fb02)
  • nuxt: Reject cross-origin paths in reloadNuxtApp (e447a793c)
  • vite: Bind vite-node IPC to a permissioned filesystem socket (1f9f4767a)
💅 Refactors
  • kit,nuxt,vite: Use es2023 array methods (#​34980)
  • nuxt: Replace runInNewContext with AST walker (d72a89ef4)
📖 Documentation
  • Document vite client and server options (#​35090)
  • Add dedicated module dependencies page (#​35171)
  • Add nodeTsConfig and sharedTsConfig options (#​35231)
  • Edit for clarity and grammar (#​35214)
🏡 Chore
✅ Tests
  • Update test for js payload rendering (bdcb81536)
  • Cover add regression test for hmr in sibling local layers (#​35125)
  • Improve reliability of hmr test (1d709b3cc)
🤖 CI
  • Always run all tests for 4.x/3.x (0dc4665cf)
  • Migrate from tibdex (ded29dc0f)
  • Add zizmor github actions check (#​35089)
  • Update to agentscan v1.8.0 (#​35120)
  • Automatically close PRs from automated accounts (#​35161)
  • Disable provenance-change enforcement in dependency-review (a2cf43e68)
❤️ Contributors

v4.4.6

Compare Source

4.4.6 is the next patch release.

👉 Changelog

compare changes

🩹 Fixes
  • vite: Use spa entry for vite-node fallback (#​35037)
  • vite: Invalidate SSR module cache when modules are invalidated via plugin hooks (a86657a0e)
  • nuxt: Match deduplicated resolveComponent calls in jsx blocks (#​35028)
  • nuxt: Prefer our own builder/server deps (#​35029)
  • nuxt: Update useFetch key even with watch: false (#​35002)
  • nitro: Mark @babel/plugin-syntax-typescript as optional peer dep (#​35041)
  • nitro: Add json extension to payload cache items (#​35043)
  • nuxt: Handle errors fetching app manifest (#​35050)
  • nuxt: Encode html-significant characters in external redirect body (#​35052)
  • nuxt: Preserve setPageLayout props on same-path navigation (#​35055)
  • vite: Don't strip buildAssetsDir from vite-node SSR ids (#​35040)
  • nuxt: Mark useLoadingIndicator properties as readonly (#​35062)
  • vite: Strip queries in css inline styles map (#​35067)
  • nitro: Validate island request hash matches props (#​35077)
  • nitro: Use regexp to strip query ([163e18d4b](https://redirect.github.com/nuxt/nuxt/commit/163e18

Note

PR body was truncated to here.


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@netlify

netlify Bot commented May 19, 2026

Copy link
Copy Markdown

Deploy Preview for nuxt-leaflet failed. Why did it fail? →

Name Link
🔨 Latest commit d7ad680
🔍 Latest deploy log https://app.netlify.com/projects/nuxt-leaflet/deploys/6a31bc74ebdb150008b1e868

@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch 2 times, most recently from 94eb338 to 9ac86d3 Compare June 2, 2026 00:10
@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch from 9ac86d3 to b1646fd Compare June 13, 2026 07:41
@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch from b1646fd to d7ad680 Compare June 16, 2026 21:13
@renovate renovate Bot changed the title chore(deps): update devdependency nuxt to v4.4.6 [security] chore(deps): update devdependency nuxt to v4.4.7 [security] Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants