Aug 6, 2026·9 min read·138 visits
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')
Improper pathname limitation and link resolution (CWE-22 and CWE-59) in the banks library prior to version 2.5.1 allow local attackers to read or write arbitrary files via crafted symbolic links in the prompt directory registry.
Improper validation of dynamic class resolution within Hazelcast's Zero Config Compact Serialization allows unauthenticated clients to trigger reflective class instantiation. This flaw can be exploited to read arbitrary JVM heap or off-heap memory, crash cluster nodes, or achieve arbitrary code execution under specific classpath conditions. This issue is resolved in Hazelcast versions 5.4.5, 5.5.10, 5.6.1, and 5.7.0.
An authentication bypass vulnerability in NearForm's fast-jwt before version 6.3.4 allows attackers to replay expired tokens due to an error in the verifier's cache expiration logic. When caching is enabled, the cache TTL defaults to 10 minutes instead of honoring the token's exp claim if the token lacks an iat claim.
CVE-2026-61427 is a critical authentication bypass and improper input validation vulnerability within the Model Context Protocol (MCP) HTTP-stream server of PraisonAI. In versions prior to 4.6.78, the server lacks authentication by default and forwards client messages directly to Python tool handlers without input validation. When bound to non-localhost interfaces, this permits unauthenticated remote attackers to perform unauthorized administrative operations and execute tools.
CVE-2026-107387 is a high-impact uncontrolled memory allocation vulnerability in music-metadata, a widely used Node.js metadata parser. The flaw occurs in the APEv2 tag parser, where the library reads an attacker-controlled 32-bit integer indicating the tag size and immediately requests a corresponding heap buffer reservation. Because this allocation occurs before validating if the input stream actually contains those bytes, an attacker can supply a minuscule audio file to trigger large, disproportionate allocations, resulting in heap exhaustion and an uncatchable process-wide Out of Memory (OOM) crash.
An input validation vulnerability exists in music-metadata versions prior to 11.16.0, where parsing a crafted MP4 file containing a sample-description (stsd) box with a zero-value size entry causes a synchronous infinite loop and memory exhaustion, resulting in complete Denial of Service.