Oct 23, 2026·5 min read·1 visit
Nuxt applications running with pages disabled fail to sanitize javascript: URIs prefixed with ASCII C0 control characters, resulting in reflected/DOM XSS when rendered within NuxtLink components.
A Cross-Site Scripting (XSS) vulnerability exists in Nuxt when configured with pages disabled (pages: false). ASCII C0 control characters prefixing javascript: URIs bypass internal protocol classification in the fallback router, allowing unauthenticated attackers to execute arbitrary script in the victim's origin context upon user interaction.
CVE-2026-114130 represents an incomplete fix for a previous vulnerability identified as CVE-2026-53722 (GHSA-934w-87qh-qr26). The issue resides in Nuxt, an open-source web application framework built on top of Vue.js, specifically affecting instances where page routing via vue-router is disabled.
When a Nuxt application sets pages: false in nuxt.config.ts, the core framework bypasses standard Vue Router primitives and delegates link rendering and navigation handling to an internal universal router (router.ts) and the <NuxtLink> component (nuxt-link.ts). This internal routing mechanism exposes an attack surface when user-supplied input is directly bound to link properties.
Under this specific configuration, input strings containing ASCII C0 control characters (range \x01 through \x1F) before the javascript: protocol scheme evade protocol detection. The framework misclassifies the malicious string as an internal relative route and renders it without proper sanitization into the HTML href attribute.
The root cause stems from a differential between Nuxt's internal URL protocol parser (ufo's hasProtocol and the framework's sanitizeExternalHref helper) and the parsing rules implemented by modern web browsers following the WHATWG URL Standard.
Prior to version 4.6.0, Nuxt evaluated whether a path bound to :to or :href was absolute or relative using regular expression replacements and protocol checks. During URL classification, functions like hasProtocol(path, { acceptRelative: true }) evaluated the raw input string before stripping leading whitespace or ASCII C0 control characters.
When input such as \x01javascript:alert(1) was passed to <NuxtLink>, hasProtocol failed to match the javascript: scheme prefix due to the prepended \x01 byte. As a result, the router treated the value as a relative path and rendered <a href="\x01javascript:alert(1)">. When a user clicks the link, web browsers strip C0 control characters during scheme extraction, restoring javascript:alert(1) and executing the payload.
The original vulnerability mitigation in sanitizeExternalHref relied on custom regex matching to sanitize control characters and strip view-source: wrappers before inspecting the scheme prefix.
// Vulnerable logic previously used in Nuxt
function sanitizeExternalHref (value: string): string | null {
let candidate = value.replace(/[\u0000-\u001F\s]+/g, '')
while (candidate.toLowerCase().startsWith('view-source:')) {
candidate = candidate.slice('view-source:'.length)
}
const colon = candidate.indexOf(':')
if (colon > 0 && isScriptProtocol(candidate.slice(0, colon + 1))) {
return null
}
return value
}In patch commit 355ed9565127ff9b1453deb7160059ed55b3cb85, the engineering team replaced custom regex parsing with standardized platform primitives utilizing the native URL web API within packages/nuxt/src/app/utils.ts.
// Patched logic in Nuxt 4.6.0
const PROBE_BASE_A = 'https://a.invalid/probe/'
const PROBE_BASE_B = 'https://b.invalid/probe/'
function parseAnchorURL (value: string, base: string = PROBE_BASE_A): URL | null {
try {
return new URL(value, base)
} catch {
return null
}
}
export function getScriptProtocol (value: string): string | null {
if (!value || isRootedPath(value)) {
return null
}
let resolved = parseAnchorURL(value.replace(/[\u0000-\u001F\u007F\s]+/g, ''))
while (resolved?.protocol === 'view-source:') {
resolved = parseAnchorURL(resolved.pathname)
}
if (!resolved) {
return ''
}
return isScriptProtocol(resolved.protocol) ? resolved.protocol : null
}
export function sanitizeAnchorHref (value: string): string | null {
return getScriptProtocol(value) === null ? value : null
}The updated implementation strips control characters and validates the URI scheme using two distinct probe base URLs (PROBE_BASE_A and PROBE_BASE_B) to verify relative versus absolute origins before rendering anchor elements.
Exploitation requires that an application configured with pages: false accepts user-supplied input and binds it to the :to or :href prop of a <NuxtLink> component.
An attacker constructs a payload by prepending an ASCII C0 control character (such as \x01 or URL-encoded %01) to a javascript: URI scheme containing JavaScript code: %01javascript:alert(document.domain).
When the server or client renders the template, <NuxtLink> inserts the string into the DOM: <a href="javascript:alert(document.domain)">Click Here</a>.
Upon user click interaction, the browser's URL parser canonicalizes the attribute value, discards \x01, identifies the javascript: scheme, and executes the payload within the context of the user's active session.
Successful exploitation leads to Cross-Site Scripting (XSS) in the context of the user's browser session. An attacker can perform actions on behalf of the user, read DOM contents, access local storage or session tokens not protected by HttpOnly flags, or hijack application state.
The official CVSS v4.0 score is rated at 2.3 (Low). The rating reflects specific attack prerequisites: the application must explicitly disable pages (pages: false), rely on vulnerable component properties, and require passive user interaction (clicking the link).
The EPSS score is measured at 0.00329 (24.75th percentile), indicating a low probability of automated exploitation in the wild. The vulnerability is not listed in the CISA KEV catalog.
The primary remediation strategy is updating the nuxt dependency to version 4.6.0 or later, which incorporates updated URL parsing logic in commit 355ed9565127ff9b1453deb7160059ed55b3cb85 and cherry-pick PR #36459.
Organizations using affected versions can verify installation status by executing npm list nuxt or reviewing package lockfiles.
> [!NOTE]
> Applications operating with standard page routing enabled (pages: true or default configuration) use vue-router directly and are not affected by this specific fallback router bug path.
In addition to upgrading, applications should enforce strict Content Security Policies (CSP) with restrictive script-src directives to mitigate the execution of unauthorized inline javascript: URIs.
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| Product | Affected Versions | Fixed Version |
|---|---|---|
nuxt Nuxt | >= 4.0.0, < 4.6.0 | 4.6.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 |
| Attack Vector | Network |
| CVSS v4.0 Score | 2.3 (Low) |
| EPSS Score | 0.00329 (24.75th percentile) |
| Impact | Cross-Site Scripting (XSS) |
| Exploit Status | poc |
| CISA KEV Status | Not Listed |
The software does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
A Stored Cross-Site Scripting (XSS) vulnerability exists in Nuxt Server Island rendering logic when utilizing the useHeadSafe composable. Raw head attributes bypass sanitization during island serialization.
Nuxt versions prior to 4.6.2 suffer from a route rule bypass vulnerability caused by an architectural mismatch in case-sensitivity handling between the Nitro server runtime and the Vue page router. An unauthenticated remote attacker can bypass server-enforced route directives—such as redirects, security headers, and SSR controls—by altering character casing in HTTP request paths.
A heap-based buffer overflow vulnerability in Pillow PyPI binary wheels (versions 11.1.0 to 12.x) allows remote code execution or application crash via crafted JPEG 2000 files processed by the bundled libopenjp2 library.
CVE-2026-109618 (dubbed PHP2Shell) is a critical vulnerability in the PHP engine core resulting from improper out-of-memory exception handling via longjmp(). When request allocation fails mid-processing, non-local control flow bypasses cleanup procedures, leaving memory structures uninitialized or in a use-after-free state during request shutdown.
CVE-2026-109619 (PHP2Shell) is a critical Use-After-Free vulnerability in the core PHP engine caused by improper global state cleanup during out-of-memory exception handling across persistent worker requests.
In Python virtualenv prior to version 21.14.9, activation script generators and configuration writers use Path.exists() before writing files. Because Path.exists() resolves symbolic links, it returns False for dangling symlinks. Consequently, virtualenv skips unlinking pre-planted symbolic links or hard links, writing data directly to target locations outside the intended virtual environment directory.