{"id":"GHSA-p4h3-4h99-9665","kind":"vulnerability","aliases":["GHSA-p4h3-4h99-9665"],"related":[],"title":"Nuxt Vite server builder wildcard `redirect` route rules can redirect to another origin","description":"### Summary\n\nUnder the experimental Vite server builder (`@nuxt/vite-server`), a wildcard `redirect` route rule whose target starts with `**` or `/**` could redirect to another origin. A request path continuing with an extra `/` or `\\` after the rule's prefix (or a path that normalises to one, such as `/old/x/..//evil.example`) produced a protocol-relative `Location` header.\n\n### Impact\n\nA wildcard `redirect` rule copies the rest of the request path onto its target. With this configuration:\n\n```ts\nexport default defineNuxtConfig({\n  server: { builder: 'vite' },\n  routeRules: {\n    '/old/**': { redirect: '/**' },\n  },\n})\n```\n\nthe server built by `nuxt build` (`.output/server/index.mjs`) redirected a request for `/old//evil.example` or `/old/\\evil.example` to `//evil.example`, which browsers follow to `evil.example`. A link to an affected site can therefore send a visitor to an origin chosen by an attacker.\n\nOnly applications that meet all of the following are affected:\n\n- They build with the experimental Vite server builder (`server: { builder: 'vite' }`), which was introduced in `4.6.0`. Applications on the default Nitro server builder (`@nuxt/nitro-server`) do not run this code.\n- They deploy its server output. Static output (`nuxt generate`) and SPA builds (`ssr: false`) have no server and are not affected.\n- They have a wildcard `redirect` rule whose target starts with `**` or `/**`, such as `'/**'` or `'/**/x'`. Targets with a path before the `**` (`'/new/**'`) stay on the same origin.\n\nNuxt 3 does not include the Vite server builder.\n\n### Patches\n\nFixed in `@nuxt/vite-server` 4.6.4, which `nuxt` 4.6.4 depends on. A run of separators (`/`, `\\` or their percent-encoded forms) at the start of the copied path now collapses to a single `/`, so the target stays on the origin it names.\n\n### Workarounds\n\nUpgrade to `nuxt` 4.6.4. If you cannot upgrade, give wildcard redirect targets a path before the `**` (for example `'/new/**'`), or build with the default Nitro server builder.","summary":"A wildcard redirect route rule in the experimental Vite server builder can turn a crafted request path into a protocol-relative Location header. A visitor following a link to the site can be sent to an origin an attacker chooses.","severity":"low","cvss":3.1,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"@nuxt/vite-server","fixed":["4.6.4"],"affected":">= 4.6.0, < 4.6.4","ecosystem":"npm"}],"ecosystems":["npm"],"tags":["cwe-601","nuxt","package","self-hosted","vite"],"not_affected_if":["nitro-server-builder","no-wildcard-redirect","spa-build","static-export"],"how_to_check":"- Check that `nuxt` or `@nuxt/vite-server` resolves to a version at or above `4.6.4` in the lockfile.\n- Look in `nuxt.config` for `server: { builder: 'vite' }` and for `routeRules` entries with a `redirect` target starting with `**` or `/**`.","fix":"- `@nuxt/vite-server` `4.6.4` (fixed version; `nuxt` `4.6.4` depends on it)\n- Workaround stated by the source: give wildcard redirect targets a path before the `**` (for example `'/new/**'`), or build with the default Nitro server builder.","status":"open","published_at":"2026-11-02T20:59:42+00:00","first_seen_at":"2026-11-09T22:53:16+00:00","triaged_at":"2026-11-09T22:58:22+00:00","updated_at":"2026-11-09T22:58:22+00:00","category":"package","confidence":0.8,"triage":{"at":"2026-11-09T22:58:22Z","model":"claude-haiku-5-5","output":{"fix":"- `@nuxt/vite-server` `4.6.4` (fixed version; `nuxt` `4.6.4` depends on it)\n- Workaround stated by the source: give wildcard redirect targets a path before the `**` (for example `'/new/**'`), or build with the default Nitro server builder.","reach":"internet","title":"Nuxt Vite server builder: wildcard redirects can send visitors to other sites","impact":"low","summary":"A wildcard redirect route rule in the experimental Vite server builder can turn a crafted request path into a protocol-relative Location header. A visitor following a link to the site can be sent to an origin an attacker chooses.","audience":"businesses","category":"package","nicknames":[],"who_cares":["nuxt","self-hosted","vite"],"confidence":0.8,"fix_status":"available","needs_auth":"no","worst_case":"visitors are redirected to an attacker-chosen external site","analyst_note":"","how_to_check":"- Check that `nuxt` or `@nuxt/vite-server` resolves to a version at or above `4.6.4` in the lockfile.\n- Look in `nuxt.config` for `server: { builder: 'vite' }` and for `routeRules` entries with a `redirect` target starting with `**` or `/**`.","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["nitro-server-builder","static-export","spa-build","no-wildcard-redirect"],"who_is_affected":"Only applications that build with the experimental Vite server builder (`server: { builder: 'vite' }`, introduced in `4.6.0`), deploy its server output, and have a wildcard `redirect` rule whose target starts with `**` or `/**`. Applications on the default Nitro builder, static generation output, SPA builds and Nuxt 3 are not affected.","user_interaction":"yes","product_ecosystem":"","needs_special_setup":"yes","severity_if_unknown":"low"},"cost_usd":0.000867,"input_tokens":5297,"output_tokens":675,"severity_before":"low"},"analyst_status":null,"analyst_note":null,"search":"'-601':26B '/evil.example':120C,168C,173C '/new':278C,353C '/old':154C,167C,170C '/old/x/..':119C '/x':271C '3':285C '4.6.0':222C '4.6.4':297C,300C,338C '4h99':17A,22A '9665':18A,23A 'affect':183C,206C,256C 'anoth':12A,95C 'applic':198C,223C 'attack':72B,196C 'browser':175C 'build':161C,208C,247C,355C 'builder':4A,43B,80C,151C,214C,216C,229C,292C,361C 'built':158C 'cannot':341C 'choos':73B 'chosen':193C 'code':235C 'collaps':321C 'configur':145C 'continu':100C 'copi':133C,318C 'could':92C 'craft':47B 'cwe':25B 'default':148C,226C,358C 'definenuxtconfig':149C 'depend':301C 'deploy':237C 'encod':311C 'evil.example':171C,178C 'exampl':352C 'experiment':40B,77C,211C 'export':147C 'extra':103C 'fals':249C 'fix':294C 'follow':59B,176C,204C 'form':312C 'generat':244C 'ghsa':15A,20A 'ghsa-p4h3-4h99':14A,19A 'give':343C 'header':56B,127C 'host':31B 'impact':128C 'includ':288C 'introduc':220C 'link':61B,180C 'locat':55B,126C 'meet':200C 'name':333C 'nitro':227C,359C 'normalis':114C 'nuxt':1A,27B,160C,243C,284C,299C,337C 'nuxt/nitro-server':230C 'nuxt/vite-server':24A,81C,296C 'one':116C 'onto':140C 'origin':13A,70B,96C,192C,283C,331C 'output':240C,242C 'output/server/index.mjs':162C 'p4h3':16A,21A 'packag':28B 'patch':293C 'path':49B,99C,112C,139C,275C,319C,348C 'percent':310C 'percent-encod':309C 'prefix':109C 'produc':121C 'protocol':53B,124C 'protocol-rel':52B,123C 'redirect':6A,10A,35B,84C,93C,131C,155C,163C,261C,345C 'relat':54B,125C 'request':48B,98C,138C,165C 'rest':135C 'rout':7A,36B,85C 'routerul':153C 'rule':8A,37B,86C,107C,132C,262C 'run':233C,304C 'self':30B 'self-host':29B 'send':187C 'sent':67B 'separ':306C 'server':3A,42B,79C,150C,157C,213C,215C,228C,239C,252C,291C,360C 'singl':324C 'site':64B,184C 'spa':246C 'ssr':248C 'start':89C,265C,315C 'static':241C 'stay':279C,328C 'summari':74C 'target':88C,142C,264C,272C,327C,346C 'therefor':186C 'ts':146C 'turn':45B 'upgrad':335C,342C 'visitor':58B,189C 'vite':2A,32B,41B,78C,152C,212C,217C,290C 'whose':87C,263C 'wildcard':5A,34B,83C,130C,260C,344C 'workaround':334C","nicknames":[],"mitigations":[],"who_affected":"Only applications that build with the experimental Vite server builder (`server: { builder: 'vite' }`, introduced in `4.6.0`), deploy its server output, and have a wildcard `redirect` rule whose target starts with `**` or `/**`. Applications on the default Nitro builder, static generation output, SPA builds and Nuxt 3 are not affected.","tier":"C","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"businesses","plain_action":null,"pkeys":["viteserver"],"ptokens":["nuxt","server","vite"],"labels":["cwe601","low","npm","nuxt","package","selfhosted","vite"],"campaign_type":null,"search_a":"'4h99':17A,22A '9665':18A,23A 'anoth':12A 'builder':4A 'ghsa':15A,20A 'ghsa-p4h3-4h99':14A,19A 'nuxt':1A 'nuxt/vite-server':24A 'origin':13A 'p4h3':16A,21A 'redirect':6A,10A 'rout':7A 'rule':8A 'server':3A 'vite':2A 'wildcard':5A","search_b":"'-601':26B 'attack':72B 'builder':43B 'choos':73B 'craft':47B 'cwe':25B 'experiment':40B 'follow':59B 'header':56B 'host':31B 'link':61B 'locat':55B 'nuxt':27B 'origin':70B 'packag':28B 'path':49B 'protocol':53B 'protocol-rel':52B 'redirect':35B 'relat':54B 'request':48B 'rout':36B 'rule':37B 'self':30B 'self-host':29B 'sent':67B 'server':42B 'site':64B 'turn':45B 'visitor':58B 'vite':32B,41B 'wildcard':34B","search_c":"'/evil.example':120C,168C,173C '/new':278C,353C '/old':154C,167C,170C '/old/x/..':119C '/x':271C '3':285C '4.6.0':222C '4.6.4':297C,300C,338C 'affect':183C,206C,256C 'anoth':95C 'applic':198C,223C 'attack':196C 'browser':175C 'build':161C,208C,247C,355C 'builder':80C,151C,214C,216C,229C,292C,361C 'built':158C 'cannot':341C 'chosen':193C 'code':235C 'collaps':321C 'configur':145C 'continu':100C 'copi':133C,318C 'could':92C 'default':148C,226C,358C 'definenuxtconfig':149C 'depend':301C 'deploy':237C 'encod':311C 'evil.example':171C,178C 'exampl':352C 'experiment':77C,211C 'export':147C 'extra':103C 'fals':249C 'fix':294C 'follow':176C,204C 'form':312C 'generat':244C 'give':343C 'header':127C 'impact':128C 'includ':288C 'introduc':220C 'link':180C 'locat':126C 'meet':200C 'name':333C 'nitro':227C,359C 'normalis':114C 'nuxt':160C,243C,284C,299C,337C 'nuxt/nitro-server':230C 'nuxt/vite-server':81C,296C 'one':116C 'onto':140C 'origin':96C,192C,283C,331C 'output':240C,242C 'output/server/index.mjs':162C 'patch':293C 'path':99C,112C,139C,275C,319C,348C 'percent':310C 'percent-encod':309C 'prefix':109C 'produc':121C 'protocol':124C 'protocol-rel':123C 'redirect':84C,93C,131C,155C,163C,261C,345C 'relat':125C 'request':98C,138C,165C 'rest':135C 'rout':85C 'routerul':153C 'rule':86C,107C,132C,262C 'run':233C,304C 'send':187C 'separ':306C 'server':79C,150C,157C,213C,215C,228C,239C,252C,291C,360C 'singl':324C 'site':184C 'spa':246C 'ssr':248C 'start':89C,265C,315C 'static':241C 'stay':279C,328C 'summari':74C 'target':88C,142C,264C,272C,327C,346C 'therefor':186C 'ts':146C 'upgrad':335C,342C 'visitor':189C 'vite':78C,152C,212C,217C,290C 'whose':87C,263C 'wildcard':83C,130C,260C,344C 'workaround':334C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-11-02T20:59:42+00:00","kev":null,"cvss_vector":null,"cvss_by":null,"poc_count":0,"sources":[{"source":"ghsa-repo","external_id":"GHSA-p4h3-4h99-9665","url":"https://github.com/nuxt/nuxt/security/advisories/GHSA-p4h3-4h99-9665","severity":"low","published_at":"2026-11-02T20:59:42+00:00","modified_at":"2026-11-02T20:59:42+00:00","first_seen_at":"2026-11-09T22:53:16+00:00","fetched_at":"2026-11-09T22:53:16+00:00","note":null}],"documents":[{"id":110429,"url":"https://github.com/nuxt/nuxt/security/advisories/GHSA-p4h3-4h99-9665","title":"Maintainer's advisory: github.com","kind":"vendor","source":"ghsa-repo","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: github.com"}],"disclosures":[],"exploit_sources":[],"notice":"Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai"}