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`
Published 16 Jun 2026 · Updated 3 Oct 2026
Affected packages
- Affected
- >=4.0.0 <4.4.7
- Fixed in
- 4.4.7
npm install nuxt@4.4.7- Affected
- >=3.5.0 <3.21.7
- Fixed in
- 3.21.7
npm install nuxt@3.21.7Details
Summary
Three weaknesses in Nuxt's client-navigation URL handling, all reachable
from documented public APIs (navigateTo and reloadNuxtApp):
1. (CVE-2026-56326) 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. (CVE-2026-56698) 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. (CVE-2026-56697) 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:
- Path-normalisation bypass in
navigateTo: - 4.x: commit `2cce6fb0`
- 3.x: commit `1f2dd5e7`
navigateTo({ open })script-protocol guard:- 4.x: #35206 (commit `3394716d`)
- 3.x: commit `62fc32ed`
- Protocol-relative bypass in
reloadNuxtApp: - 4.x: commit `e447a793`
- 3.x: commit `6497d99d`
Workarounds
- For (1): validate redirect targets before passing them to
navigateTo, for example reject any input wherenew URL(target, 'http://localhost').pathnamestarts 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:andhttps:) before passing it tonavigateTo({ open: ... }). - For (3): same shape as (1). Reject paths starting with
//(or wherenew URL(path, window.location.href).host !== window.location.host) before passing toreloadNuxtApp({ 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.
Is GHSA-c9cv-mq2m-ppp3 in any of your client repos?
Checking one package by hand is fine. Checking it across forty client projects is not. NPMscan reads the lockfiles in every GitHub repo you pick, finds each project with an affected nuxt, and gives you the command that fixes it.
References
- Linkgithub.com/nuxt/nuxt/security/advisories/GHSA-c9cv-mq2m-ppp3
- Advisorynvd.nist.gov/vuln/detail/CVE-2026-56326
- Advisorynvd.nist.gov/vuln/detail/CVE-2026-56697
- Advisorynvd.nist.gov/vuln/detail/CVE-2026-56698
- Linkgithub.com/nuxt/nuxt/pull/35115
- Linkgithub.com/nuxt/nuxt/pull/35206
- Linkgithub.com/nuxt/nuxt/commit/1f2dd5e78c77576437138e97671965573c232835
- Linkgithub.com/nuxt/nuxt/commit/2cce6fb02e621196d56df92e05594e07469b5a6d
- Linkgithub.com/nuxt/nuxt/commit/3394716d4a913cba904b028df5338f2aead50032
- Linkgithub.com/nuxt/nuxt/commit/62fc32eddf648b00a3890141e0235d2a222b024d
- Linkgithub.com/nuxt/nuxt/commit/6497d99dd106254abd089f6a263d7773869a343b
- Linkgithub.com/nuxt/nuxt/commit/e447a793c47766834f7497f8412a76cd56fd8ee1
- Packagegithub.com/nuxt/nuxt
- Linkwww.vulncheck.com/advisories/nuxt-cross-site-scripting-via-navigateto-open-option
- Linkwww.vulncheck.com/advisories/nuxt-open-redirect-via-protocol-relative-paths-in-reloadnuxtapp
- Linkwww.vulncheck.com/advisories/nuxt-server-side-open-redirect-via-path-normalization-bypass-in-navigateto
Advisory data from OSV.dev (opens OSV.dev in a new tab), refreshed daily.