On 5 October 2026 the Handlebars.js maintainers released handlebars 4.7.10 and published three advisories, two rated Critical. Both Critical issues let an attacker run JavaScript on the server. The GitHub Advisory Database added them on 8 October as CVE-2026-106446, CVE-2026-106445 and CVE-2026-106444.
Handlebars is everywhere in Node.js: Express view engines, email templating, static site tools, code generators. Most of those uses compile template files the developer wrote. The advisories are precise about what has to be different for an attacker to get in.
What's affected
All three are fixed in handlebars 4.7.10.
CVE-2026-106446, Critical: AST type confusion in compile(). Handlebars.compile() and Handlebars.precompile() accept either a template string or a pre-parsed AST object. Version 4.7.9 added validation for ASTs after earlier advisories, but it only checked certain node types. Several other AST values are written into the generated JavaScript unchecked, and one of them works with default compile options. Affected: 4.0.0 through 4.7.9.
The advisory's example is an Express route that calls Handlebars.compile(req.body.text). With express.json(), text can be an object, not a string, and the object carries the injected code. The advisory states it plainly: "Applications that only ever pass template strings are not affected."
CVE-2026-106445, Critical: own-property check bypass. Handlebars blocks dangerous property names like constructor on prototypes. But constructor is an own property of every prototype object, and the lookup trusted own properties before checking the deny list. A template that reaches Function.prototype can pull out the Function constructor and execute code. The precondition is rendering an attacker-controlled template with allowProtoMethodsByDefault: true. Affected: 3.0.0 through 4.7.9.
The advisory adds a warning worth acting on: if you use packages like hbs, which it says set allowProtoMethodsByDefault: true by default, you have to update Handlebars.
CVE-2026-106444, Moderate: unsafe inline embedding of precompiled templates. precompile() copied a closing script tag in template text into its output unchanged. If you precompile attacker-controlled templates and paste the output into an inline script element, the browser closes the script early and runs whatever follows. Server-side rendering and precompiled templates served as external .js files are not affected. Affected: 4.0.0 through 4.7.9.
How to check if you're exposed
Find every copy of Handlebars and the wrappers that pull it in:
npm ls handlebars hbs express-handlebars --all
Now find where templates come from. The key question is whether anything other than a file you wrote reaches compile() or precompile():
grep -rnE "Handlebars\.(compile|precompile)\(|hbs\.compile\(" src/ lib/ | grep -v node_modules
grep -rn "allowProtoMethodsByDefault" src/ lib/ node_modules/hbs 2>/dev/null
Review each call site:
- Argument is a file read from your repo or a string literal. Not reachable for CVE-2026-106446 or CVE-2026-106444.
- Argument comes from a request, a database row users can edit, or an admin "custom template" feature. Reachable. That includes email template editors, notification templates, white-label themes and anything else that lets a tenant author Handlebars.
- The rendering path sets
allowProtoMethodsByDefault: trueand renders templates users can author. Reachable for CVE-2026-106445.
Admin-only template editors still count. In a multi-tenant app, "admin" often means a customer's admin, and code execution on your server is a much bigger privilege than editing a template.
What to do now
-
Upgrade to handlebars 4.7.10. If a wrapper pins an older range, force it with npm
overrides:{ "overrides": { "handlebars": "4.7.10" } } -
Type-check before compiling. Reject anything that isn't a string. This one check closes the AST path in CVE-2026-106446 even on older versions:
if (typeof source !== 'string') throw new TypeError('template must be a string') const template = Handlebars.compile(source) -
Turn off
allowProtoMethodsByDefaultanywhere untrusted templates are rendered, and allow specific methods withallowedProtoMethodsinstead. -
Serve precompiled templates as external files rather than inlining them in HTML.
-
Treat user-authored templates as code. Run them in a separate process with no secrets in its environment, or move to a logic-less format if users only need placeholders.
Why it matters
Template engines are interpreters. Any feature that lets a user supply a template is a feature that lets a user write a small program, and the engine's sandbox is the only thing between that program and your server. Handlebars has hardened that sandbox several times, and each round has found another gap.
That doesn't make every Handlebars install urgent. A blog that renders .hbs files from its own repo can't be reached through either Critical bug. A SaaS product with a "customize your email" screen probably can. Same package, same version, very different risk.
Try it yourself
Run the grep above on one Node.js service and list every compile() call with the source of its argument. Add the string type check to the one closest to user input, write a unit test that passes an object, and confirm it now throws.
Click through it at your own pace, or open it full screen.
Quick check
An Express app renders views/*.hbs files from its own repository. Is CVE-2026-106446 reachable?
Not through those views. The bug needs an untrusted object passed to compile() or precompile(). Templates read from your own files are strings you wrote.
What setting does CVE-2026-106445 depend on?
allowProtoMethodsByDefault: true combined with rendering an attacker-controlled template. The advisory notes that some wrappers, such as hbs, set it by default.
Is a precompiled template served as an external JavaScript file affected by CVE-2026-106444?
No. The issue only appears when precompiled output is embedded directly inside an inline script element in HTML.