Handlebars (41.5M weekly downloads): the March AST validation is bypassed, so an object passed to compile() still runs attacker JavaScript (CVE-2026-106446, 9.8), and the prototype deny list misses Function.prototype.constructor (CVE-2026-106445, 9.2); fixed 4.7.10; exploitable only where untrusted objects reach compile() or allowProtoMethodsByDefault is on
TL;DR
Handlebars (41,542,245 npm downloads in the week to 2026-10-07) fixed two JavaScript-injection bugs in 4.7.10 on 2026-10-05. CVE-2026-106446 (CVSS 9.8): Handlebars.compile() and precompile() accept a pre-parsed AST object as well as a template string; version 4.7.9 (2026-03-26, for CVE-2026-33937) added validation for only three node types, and the compiler still writes other AST fields such as Program.blockParams.length straight into generated JavaScript. An application that passes an untrusted object, for example a parsed JSON body, to compile() runs attacker code when the template renders; with precompile() the code is embedded in the output and runs wherever that is loaded. CVE-2026-106445 (CVSS 4.0 9.2): lookupProperty returns Function.prototype.constructor before the prototype-access deny list runs, so a template rendered with allowProtoMethodsByDefault: true and a function in its context can reach the Function constructor. Applications that only ever pass template strings to compile() and keep the default proto settings are not affected by either. Upgrade to 4.7.10 anyway; the scanner noise alone will force it.
What happened
The maintainers published both advisories on the repository on 2026-10-05, GitHub as CNA issued the CVEs on 2026-10-06, and the reviewed-critical npm listing carried both on 2026-10-08.
CVE-2026-106446 (GHSA-8r5x-fm3f-whwj), 9.8, CWE-94/843, 4.0.0 to 4.7.9, fixed 4.7.10. This is the second incomplete-fix round for the same entry point. In March, CVE-2026-33937 (9.8) showed that a NumberLiteral.value in a crafted AST was emitted unquoted into generated code, and CVE-2026-33940 (8.1) showed a dynamic partial lookup could hand an object to env.compile(); 4.7.9 added a validator for PathExpression, NumberLiteral and BooleanLiteral nodes. The new advisory lists the fields the validator never looked at: Program.blockParams.length works with default options; depth, a non-string StringLiteral.value and a non-string PathExpression.original need stringParams: true. Sixteen reporters are credited across three variants, including Team Atlanta and Shopify's open-source security team, which is the pattern of a bug class being fuzzed in parallel once the first instance is public.
CVE-2026-106445 (GHSA-p8wg-vrv2-v86f), 9.2 (CVSS 4.0, AT:P), CWE-184/1289, 4.0.0 to 4.7.9, fixed 4.7.10. The runtime's prototype-access protection uses a deny list, but constructor is an own property of Function.prototype, so the lookup succeeds before the list is consulted. The precondition is a template the attacker controls, rendered with allowProtoMethodsByDefault: true, and a function reachable from the context. The vendor's workaround is simply not to set that option for untrusted templates. Reporter brandon-t-elliott.
Who is actually exposed. The 9.8 is an unauthenticated network score for the shape "server passes a request body to compile()". Most generated apps compile string templates from their own source tree, where neither bug applies. The exposed shapes are: a template editor or notification service that stores user-supplied templates and compiles them per request; an API that accepts JSON and forwards it to compile() without a type check; or a build pipeline that precompiles templates from untrusted input. Filed high rather than critical for that reason, with both registry scores shown.
Am I affected?
npm ls handlebars 2>/dev/null # anything below 4.7.10
grep -rn "Handlebars.compile\|Handlebars.precompile\|allowProtoMethodsByDefault\|stringParams" --include=*.js --include=*.ts . | grep -v node_modules | head
If every compile() call site receives a string literal or a string read from your own files, you are not exploitable on any version. If any call site can receive a parsed object, or you set allowProtoMethodsByDefault: true for user templates, you are.
If you are affected
- Upgrade
handlebarsto 4.7.10 or later; regenerate the lockfile. - Add
typeof template === 'string'before everycompile()/precompile()call, and reject anything else. The vendor lists this as the workaround for both March and October bugs. - Servers that only render precompiled templates should import
handlebars/runtime, wherecompile()does not exist. - Do not set
allowProtoMethodsByDefault: truefor templates you did not write. - If an untrusted object could have reached
compile()on an affected version, treat it as code execution and follow if-your-webapp-was-compromised.md.
Prevention
Template engines are compilers; give them strings, never structures from the network (auditing-a-vibe-coded-repo.md). Keep the runtime-only build in production, and let npm audit block the deploy when a 9.8 lands in a library this widely installed (npm-hardening.md).
Sources
- GitHub Advisory Database — GHSA-8r5x-fm3f-whwj: Handlebars: JavaScript Injection via AST Type Confusion in compile (bypass of CVE-2026-33937) (fetched 2026-10-09; CVE-2026-106446, 9.8
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H, 4.0.0 to 4.7.9 → 4.7.10, repository 2026-10-05, NVD 2026-10-06, database 2026-10-08, unchecked fields, workarounds, PR #2185, credits) - GitHub Advisory Database — GHSA-p8wg-vrv2-v86f: Handlebars: JavaScript Injection via Own Property Check Bypass (CVE-2026-106445, CVSS 4.0 9.2
AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H, 4.0.0 to 4.7.9 → 4.7.10,allowProtoMethodsByDefaultprecondition and workaround, reporter brandon-t-elliott) - CVE Services — CVE-2026-106446 and CVE-2026-106445 (GitHub as CNA, published 2026-10-06; affected
>= 4.0.0, < 4.7.10) - GitHub Advisory Database — GHSA-2w6w-674q-4c4q (CVE-2026-33937) and GHSA-xhpv-hc6g-r9c6 (CVE-2026-33940) (the March 2026 pair fixed in 4.7.9; repository 2026-03-26)
- GitHub Advisory Database — reviewed critical npm listing (both rows on 2026-10-08);
api.npmjs.orgweekly download point forhandlebars(41,542,245, 2026-10-01 to 10-07) andnpm view handlebars version(4.7.10), checked 2026-10-09