Aug 6, 2026·9 min read·1 visit
Unauthenticated Remote Code Execution (RCE) in Nuxt via Server-Side Template Injection (SSTI) when the Vue runtime compiler is enabled, triggered through crafted props sent to Server Island endpoints.
A highly critical Server-Side Remote Code Execution (RCE) vulnerability exists in the Nuxt framework when Server Islands and the Vue runtime compiler are simultaneously enabled. This allows unauthenticated remote attackers to execute arbitrary system commands on the host process by passing a crafted component definition object to the dynamic component resolution engine via public island endpoints.
Nuxt Server Islands represent a specialized component rendering paradigm designed to isolate heavy or dynamic components on the server side, serving their HTML or JSON representations on demand. This isolation reduces the bundle size delivered to the client while preserving the benefits of server-side reactivity. When a client needs to re-render a server island, the Nuxt frontend communicates with a standardized public API endpoint located at /__nuxt_island/. This endpoint is exposed to the internet and is intended to process user-controlled parameters, known as component props, dynamically.
The dynamic nature of Nuxt Server Islands introduces an attack surface when paired with Vue's polymorphic component structures. Polymorphic components rely on dynamic tag binding (such as Vue's <component :is> primitive) to allow the root tag of an element to be changed dynamically at runtime based on component props. When these polymorphic elements receive unvalidated, client-supplied props, they expose a pathway to pass raw objects into Vue's dynamic component resolution engine instead of simple string tags.
Under normal conditions, this structural flexibility does not lead to code execution because Vue packages are compiled ahead of time, leaving the server bundle without compilation capabilities. However, when developers explicitly enable the optional Vue runtime compiler via the configuration setting vue.runtimeCompiler: true, the application includes the full template compilation suite within the server-side Nitro bundle. This specific configuration transforms dynamic tag resolution sinks into immediate Server-Side Template Injection (SSTI) and Server-Side Remote Code Execution (RCE) vectors.
The root cause of this vulnerability lies in the interaction between Vue's attribute fallthrough mechanism and the runtime compilation behaviors of polymorphic components. In the Vue architecture, any attribute or prop supplied to a component that is not explicitly declared in its props definition falls through to the root HTML element. When the root element is a polymorphic component (such as the wrappers used in component libraries like @nuxt/ui or reka-ui), it receives these unvalidated attributes and binds them to dynamic tags using bindings like <component :is="as"> or <component :is="asChild">.
While developers expect the parameter bound to the dynamic tag to be a simple HTML tag string like 'div' or 'button', Vue's component resolution engine allows the binding value to be a raw component descriptor object. When an attacker passes a JSON object containing a template property as the value for this parameter, Vue treats the object as a local component definition. If the server process has access to the Vue runtime compiler, Vue attempts to compile the HTML or template code specified in that template property on-the-fly.
Once compiled, this template is executed during the Server-Side Rendering (SSR) cycle within the server-side Nitro runtime. Vue template expressions execute in a sandbox context; however, standard sandbox escape techniques can easily bypass this boundary. By accessing the constructor property of standard types, an attacker can access the global Function constructor to instantiate and run arbitrary JavaScript. Because this execution occurs inside the Node.js process hosting the Nitro server, it yields full operating system command execution capabilities.
To understand the patch implementation, we must examine how the vulnerability was addressed in the Nuxt core codebase. In vulnerable versions, incoming properties parsed from the query string or request body were forwarded directly to the server-side rendering pipeline without key verification. The fix introduces a recursive validation utility, findUnsafeIslandPropKey, located in packages/nuxt/src/app/island-props.ts. This function performs a deep depth-first traversal of the props structure to detect any key matching the string 'template'.
// packages/nuxt/src/app/island-props.ts
export type UnsafeIslandPropKey = 'template'
export function findUnsafeIslandPropKey (value: unknown): UnsafeIslandPropKey | undefined {
const pending = [value]
const seen = new Set<object>()
while (pending.length) {
const current = pending.pop()
if (!current || typeof current !== 'object' || seen.has(current)) {
continue
}
seen.add(current)
for (const key of Object.keys(current)) {
if (key === 'template') {
return key
}
pending.push((current as Record<string, unknown>)[key])
}
}
}The function uses an iterative queue array named pending rather than recursion to avoid stack overflow risks on deeply nested payloads. It also maintains a seen set to track object references, protecting against infinite loops from circular structures. If any property key strictly equals 'template', the validation instantly returns the key, causing the calling endpoint handler to abort the execution.
In the server island endpoint code (packages/nitro-server/src/runtime/handlers/island.ts), the validation is conditional on the runtime compiler setting to avoid disrupting legitimate use cases. If runtimeCompiler is enabled and an unsafe key is found, the server throws an HTTP 400 Bad Request error:
// packages/nitro-server/src/runtime/handlers/island.ts
if (runtimeCompiler && findUnsafeIslandPropKey(parsedProps)) {
if (import.meta.dev) {
serverDiagnostics.NUXT_E8005()
}
throw createError({ statusCode: 400, statusMessage: 'Invalid island request props' })
}While this fix mitigates the direct attack vector, it relies on Object.keys() to identify keys in the parsed object. Object.keys() only returns an object's own enumerable properties, which creates a potential bypass route through prototype pollution. If an attacker can pollute the Object.prototype with a template property via a separate vulnerability, this validation utility will bypass the check since template will not be an 'own' property of the parsed prop object. However, Vue's internal component resolver will still access the polluted property via prototype chain lookup, leading to compilation and execution of the injected template.
Exploiting CVE-2026-71320 requires an attacker to identify an application running a vulnerable version of Nuxt that exposes a Server Island component and has the runtime compiler option enabled. The attacker then constructs a payload that passes an options object containing a malicious template string to a polymorphic component property. The entry point is the public route /__nuxt_island/<Component> where props can be supplied via a URL-encoded query parameter.
The attacker crafts a payload targeting a polymorphic element like a dynamic button. The payload specifies the dynamic rendering tag as an object with the nested template property containing standard sandbox-escaping primitives to execute shell commands. This object structure forces the Vue engine to compile the string on-the-fly.
{
"as": {
"template": "<div>{{constructor.constructor('return globalThis.process.mainModule.require(\"child_process\").execSync(\"id\").toString()')()}}</div>"
}
}When URL-encoded and sent to the endpoint, the application receives the query parameter, parses the JSON structure, and passes the "as" parameter downstream. Vue treats the object as a component descriptor, compiles the template, and renders it. The template expression executes, escapes the Vue sandbox, runs the id shell command, and returns the output to the client in the HTTP response.
The impact of CVE-2026-71320 is critical, as successful exploitation results in immediate Server-Side Remote Code Execution (RCE) with the privileges of the Node.js/Nitro server process. This level of access grants the attacker complete control over the application's runtime environment. Attackers can read sensitive files (such as configuration files, SSH keys, and system logs), access local databases, or exfiltrate environment variables containing cloud provider API keys and database credentials.
Once an attacker achieves code execution inside the Nitro process, they can pivot to execute attacks against internal network resources that are otherwise isolated from the public internet. If the application runs in a containerized environment (such as Kubernetes or Docker), the attacker can seek to compromise the underlying host or access adjacent container services. This vulnerability is especially critical for cloud-native applications where server processes are deeply integrated with service accounts and cloud identity management roles.
The CVSS v3.1 vector string for this vulnerability is CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H, giving it a base score of 8.1. The attack complexity is rated as High because exploitation depends on the presence of specific conditions: the vue.runtimeCompiler setting must be enabled, and the application must feature a server island component with a polymorphic element. However, when these conditions are met, no authentication is required, and exploitation is highly reliable, presenting a severe risk to affected deployments.
The primary and most effective remediation path is to upgrade the Nuxt core package to a patched release. For deployments utilizing the Nuxt 3.x release line, the framework must be updated to version 3.21.10 or higher. For deployments running the Nuxt 4.x release line, the framework must be updated to version 4.5.1 or higher. These updates contain the recursive property validation utility that filters dangerous input before it reaches the rendering engine.
If upgrading immediately is not possible, developers should disable the Vue runtime compiler by ensuring vue.runtimeCompiler is set to false in nuxt.config.ts. Because this option is disabled by default, most applications do not require it and can be secured instantly by removing the configuration line. This disables the dynamic compilation of templates at runtime, rendering any injected template strings inert and preventing code execution.
// nuxt.config.ts
export default defineNuxtConfig({
vue: {
runtimeCompiler: false // Disables the dynamic compilation vulnerability vector
}
})As a defense-in-depth measure, security teams can implement Web Application Firewall (WAF) rules to detect and block malicious payloads targeting the server island endpoint. WAF rules should inspect both query parameters and request bodies for requests directed to paths matching /__nuxt_island/. The rules should search for the presence of the "template" key within JSON payloads, blocking any request that attempts to pass this key to the server island endpoint.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
Nuxt Nuxt | >= 3.4.0, < 3.21.10 | 3.21.10 |
Nuxt Nuxt | >= 4.0.0, < 4.5.1 | 4.5.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-94: Improper Control of Generation of Code ('Code Injection') |
| Attack Vector | Network (AV:N) |
| CVSS v3.1 Score | 8.1 (High) |
| EPSS Score | Not Registered / New CVE |
| Impact | Server-Side Remote Code Execution (RCE) |
| Exploit Status | Proof-of-Concept (PoC) |
| KEV Status | Not Listed |
Improper Control of Generation of Code ('Code Injection')
An unauthenticated remote denial of service vulnerability exists in the Nuxt framework island renderer endpoint. By transmitting large or deeply nested JSON payloads, an attacker can block the single-threaded Node.js event loop, resulting in application-wide CPU exhaustion before signature verification occurs.
CVE-2026-65601 is a critical security vulnerability within Traefik's implementation of the Kubernetes Gateway API. Due to variable reuse and incorrect namespace resolution logic in the routing engine, Traefik resolved custom extension filters (such as Traefik CRD Middlewares) inside a target backend service's namespace rather than the originating HTTPRoute's namespace. This flaw enables a low-privileged tenant to bypass namespace isolation boundaries and invoke highly privileged middleware components in foreign namespaces to which they only have service-level routing access.
An authorization bypass vulnerability in Traefik allows low-privileged users within unauthorized Kubernetes namespaces to reference privileged file-provider TCP serversTransports via IngressRouteTCP resources, bypassing the crossProviderNamespaces constraint.
An unauthenticated remote denial of service (DoS) vulnerability exists in Nuxt's server component ('island') rendering mechanism. Due to a deterministic signature generation scheme and missing input constraints on server-side v-for directive expansion, an attacker can trigger unconstrained memory allocations on the hosting Node.js server, leading to immediate process crash.
A security vulnerability in Electron's contextBridge allows untrusted renderer contexts to bypass context isolation. By passing an object with a crafted __proto__ property, an attacker can pollute the prototype chain of objects copied into the privileged preload context. This occurs because Electron's C++ property copying layer used standard V8 property assignment, which executes prototype setters. This bypasses Electron's context isolation security boundary, potentially enabling remote code execution (RCE) or privileges escalation. The vulnerability has been addressed in Electron versions 39.8.9, 40.9.2, 41.2.2, and 42.0.0-beta.4.
A high-severity sandbox escape and arbitrary command execution vulnerability exists in the Electron desktop framework prior to versions 39.8.9, 40.9.2, 41.2.1, and 42.0.0-beta.3. The flaw lies in the handling of DevTools embedder messages during file manager reveal actions, allowing an attacker to execute arbitrary binaries with main process privileges.