{"id":"CVE-2026-114130","kind":"vulnerability","aliases":["CVE-2026-114130","GHSA-jjm6-p2m9-9w4x"],"related":[],"title":"Nuxt: Incomplete fix for GHSA-934w-87qh-qr26: a `javascript:` URL prefixed with an ASCII control character executes from `<NuxtLink>` when `pages` is disabled","description":"## Impact\n\nAn application that renders `<NuxtLink :to=\"...\">` with a value it does not control can be made to render an anchor whose `href` executes script in the application's origin when clicked.\n\nThis is an incomplete fix for [GHSA-934w-87qh-qr26](https://github.com/nuxt/nuxt/security/advisories/GHSA-934w-87qh-qr26) (CVE-2026-53722). It only affects applications running without a `pages/` directory, where `pages` resolves to `false` and Nuxt registers its own router in place of vue-router. Applications using vue-router are not affected.\n\nPrefixing `javascript:` with an ASCII C0 control character, for example `%01`, meant the value was not recognised as having a protocol. It was classified as an internal route and so never reached the protocol check added in GHSA-934w-87qh-qr26, and the router used for `pages: false` passed it through to the rendered `href` unchanged. Browsers strip the leading control character and run the result as a script URL.\n\nBoth `<NuxtLink custom>` and the default anchor are affected, and the `href` is present in the server-rendered HTML.\n\n## Mitigating factors\n\n- The application must have `pages` disabled (no `pages/` directory, or `pages: false`).\n- The application must bind untrusted input to `:to`.\n- A victim must click the rendered link.\n\n## Affected versions\n\n`nuxt` `<4.6.0`, including all Nuxt 3 releases. Versions before `4.4.7` and `3.21.7` are also affected by GHSA-934w-87qh-qr26.\n\n## Patches\n\nFixed in `nuxt@4.6.0`. Nuxt 3 reached end of life on 31 July 2026 and will not receive a fix.\n\nAnchor `href` values are now checked for script-capable protocols wherever they are rendered, including the router used when `pages` is disabled. Protocol detection also moved to the platform `URL` parser, so a URL is classified the same way the browser will read it.\n\n## Workarounds\n\nUpgrade to `nuxt@4.6.0` or later. If you cannot upgrade, including on Nuxt 3, validate values before binding them to `:to`, for example by rejecting anything that is not a path beginning with a single `/`.","summary":"Nuxt's NuxtLink component, when the app runs without a pages/ directory, renders a javascript: URL href that is prefixed with an ASCII control character and slips past the existing protocol check. If an attacker controls the :to value and a victim clicks the link, script runs in the application's origin.","severity":"low","cvss":2.3,"epss":0.003289999905973673,"exploited":false,"exploited_at":null,"products":[{"name":"nuxt","fixed":["4.6.0"],"affected":"< 4.6.0","ecosystem":"npm"}],"ecosystems":["npm"],"tags":["cwe-79","javascript","nuxt","package","self-hosted"],"not_affected_if":["no-untrusted-to-binding","nuxt-4.6.0-or-later","pages-directory-present","vue-router-in-use"],"how_to_check":"Check for a pages/ directory in the project and whether nuxt.config sets pages: false; if neither applies to the app, check whether any <NuxtLink :to> binds untrusted input.\nRun npm ls nuxt to see the installed version.","fix":"Upgrade nuxt to 4.6.0 or later; Nuxt 3 gets no fix (end of life 31 July 2026).\nIf upgrade is not possible, validate :to values so only paths beginning with a single / are accepted.","status":"open","published_at":"2026-10-21T18:17:25+00:00","first_seen_at":"2026-10-23T19:11:31+00:00","triaged_at":"2026-10-23T20:06:34+00:00","updated_at":"2026-10-23T21:57:29+00:00","category":"package","confidence":0.85,"triage":{"at":"2026-10-23T20:06:34Z","model":"claude-haiku-5-5","output":{"fix":"Upgrade nuxt to 4.6.0 or later; Nuxt 3 gets no fix (end of life 31 July 2026).\nIf upgrade is not possible, validate :to values so only paths beginning with a single / are accepted.","summary":"Nuxt's NuxtLink component, when the app runs without a pages/ directory, renders a javascript: URL href that is prefixed with an ASCII control character and slips past the existing protocol check. If an attacker controls the :to value and a victim clicks the link, script runs in the application's origin.","category":"package","who_cares":["nuxt","self-hosted","javascript"],"confidence":0.85,"analyst_note":"","how_to_check":"Check for a pages/ directory in the project and whether nuxt.config sets pages: false; if neither applies to the app, check whether any <NuxtLink :to> binds untrusted input.\nRun npm ls nuxt to see the installed version.","needs_analyst":false,"not_affected_if":["vue-router-in-use","pages-directory-present","no-untrusted-to-binding","nuxt-4.6.0-or-later"],"severity_if_unknown":"low"},"cost_usd":0.000472,"input_tokens":2745,"output_tokens":396,"severity_before":"low"},"analyst_status":null,"analyst_note":null,"search":"'-114130':27A,35A '-2026':26A,34A,142C '-53722':143C '-79':38B '/nuxt/nuxt/security/advisories/ghsa-934w-87qh-qr26)':140C '01':188C '2026':333C '3':303C,325C,399C '3.21.7':309C '31':331C '4.4.7':307C '4.6.0':299C,323C,389C '87qh':8A,136C,218C,317C '934w':7A,135C,217C,316C '9w4x':32A 'add':213C 'affect':146C,177C,255C,296C,312C 'also':311C,365C 'anchor':115C,253C,340C 'anyth':411C 'app':51B 'applic':94B,99C,122C,147C,170C,270C,282C 'ascii':16A,67B,182C 'attack':79B 'begin':417C 'bind':284C,403C 'browser':235C,381C 'c0':183C 'cannot':394C 'capabl':349C 'charact':18A,69B,185C,240C 'check':76B,212C,345C 'classifi':201C,376C 'click':87B,126C,292C 'compon':48B 'control':17A,68B,80B,108C,184C,239C 'cve':25A,33A,141C 'cwe':37B 'default':252C 'detect':364C 'directori':56B,152C,277C 'disabl':24A,274C,362C 'end':327C 'exampl':187C,408C 'execut':19A,118C 'exist':74B 'factor':268C 'fals':157C,226C,280C 'fix':3A,131C,320C,339C 'ghsa':6A,29A,134C,216C,315C 'ghsa-934w-87qh-qr26':5A,133C,215C,314C 'ghsa-jjm6-p2m9-9w4x':28A 'github.com':139C 'github.com/nuxt/nuxt/security/advisories/ghsa-934w-87qh-qr26)':138C 'host':44B 'href':61B,117C,233C,258C,341C 'html':266C 'impact':97C 'includ':300C,355C,396C 'incomplet':2A,130C 'input':286C 'intern':204C 'javascript':11A,39B,59B,179C 'jjm6':30A 'juli':332C 'later':391C 'lead':238C 'life':329C 'link':89B,295C 'made':111C 'meant':189C 'mitig':267C 'move':366C 'must':271C,283C,291C 'never':208C 'nuxt':1A,36A,40B,45B,159C,298C,302C,322C,324C,388C,398C 'nuxtlink':47B 'origin':96B,124C 'p2m9':31A 'packag':41B 'page':22A,55B,151C,154C,225C,273C,276C,279C,360C 'parser':371C 'pass':227C 'past':72B 'patch':319C 'path':416C 'place':165C 'platform':369C 'prefix':13A,64B,178C 'present':260C 'protocol':75B,198C,211C,350C,363C 'qr26':9A,137C,219C,318C 'reach':209C,326C 'read':383C 'receiv':337C 'recognis':194C 'regist':160C 'reject':410C 'releas':304C 'render':57B,101C,113C,232C,265C,294C,354C 'resolv':155C 'result':244C 'rout':205C 'router':163C,169C,174C,222C,357C 'run':52B,91B,148C,242C 'script':90B,119C,247C,348C 'script-cap':347C 'self':43B 'self-host':42B 'server':264C 'server-rend':263C 'singl':420C 'slip':71B 'strip':236C 'unchang':234C 'untrust':285C 'upgrad':386C,395C 'url':12A,60B,248C,370C,374C 'use':171C,223C,358C 'valid':400C 'valu':83B,104C,191C,342C,401C 'version':297C,305C 'victim':86B,290C 'vue':168C,173C 'vue-rout':167C,172C 'way':379C 'wherev':351C 'whose':116C 'without':53B,149C 'workaround':385C","nicknames":[],"mitigations":[],"who_affected":null,"tier":"C","verified":{},"analyst_revisit_at":null,"first_public_at":"2026-10-21T18:17:25+00:00","kev":null,"cvss_vector":"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/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","cvss_by":"security-advisories@github.com","poc_count":0,"sources":[{"source":"ghsa","external_id":"GHSA-jjm6-p2m9-9w4x","url":"https://github.com/advisories/GHSA-jjm6-p2m9-9w4x","severity":"low","published_at":"2026-10-22T16:51:37+00:00","modified_at":"2026-10-22T16:51:39+00:00","first_seen_at":"2026-10-23T19:11:31+00:00","fetched_at":"2026-10-23T19:11:31+00:00","note":null},{"source":"nvd","external_id":"CVE-2026-114130","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-114130","severity":null,"published_at":"2026-10-21T18:17:25+00:00","modified_at":"2026-10-22T16:46:48+00:00","first_seen_at":"2026-10-23T21:57:29+00:00","fetched_at":"2026-10-23T22:29:01+00:00","note":null}],"documents":[],"notice":"Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai"}