GitHub Advisoryadvisory · npm

GHSA-9cx6-37pm-9jff Handlebars.js has Denial of Service via Malformed Decorator Syntax in Template Compilation

HIGH Published 2026-03-27 Modified 2026-03-30 Official page ↗
Aliases
CVE-2026-33939
Ecosystem
npm
Packages
handlebars
Severity
High
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weaknesses
CWE-754
Reviewed
2026-03-27

Affected packages

• npm handlebars: >= 4.0.0, < 4.7.9 → fixed in 4.7.9

Description

Summary When a Handlebars template contains decorator syntax referencing an unregistered decorator (e.g. `{{*n}}`), the compiled template calls `lookupProperty(decorators, "n")`, which returns `undefined`. The runtime then immediately invokes the result as a function, causing an unhandled `TypeError: ... is not a function` that crashes the Node.js process. Any application that compiles user-supplied templates without wrapping the call in a `try/catch` is vulnerable to a single-request Denial of Service. Description In `lib/handlebars/compiler/javascript-compiler.js`, the code generated for a decorator invocation looks like: ```javascript fn = lookupProperty(decorators, "n")(fn, props, container, options) || fn; ``` When `"n"` is not a registered decorator, `lookupProperty(decorators, "n")` returns `undefined`. The expression immediately attempts to call `undefined` as a function, producing: ``` TypeError: lookupProperty(...) is not a function ``` Because the error is thrown inside the compiled template function and is not caught by the runtime, it propagates up as an unhandled exception and — when not caught by the application — crashes the Node.js process. This inconsistency is notable: references to unregistered helpers produce a clean `"Missing helper: ..."` error, while references to unregistered decorators cause a hard crash. Attack scenario: An attacker submits `{{*n}}` as template content to any endpoint that calls `Handlebars.compile(userInput)()`. Each request crashes the server process; with process managers that auto-restart (PM2, systemd), repeated submissions create a persistent DoS. Proof of Concept ```javascript const Handlebars = require('handlebars'); // Handlebars 4.7.8, Node.js v22.x // Any of these payloads crash the process Handlebars.compile('{{*n}}')({}); Handlebars.compile('{{*decorator}}')({}); Handlebars.compile('{{*constructor}}')({}); ``` Expected crash output: ``` TypeError: lookupProperty(...) is not a function at Function.eval [as decorator] (eval at compile (...javascript-compiler.js:134:36)) ``` Workarounds • Wrap compilation and rendering in `try/catch`: ```javascript try { const result = Handlebars.compile(userInput)(context); res.send(result); } catch (err) { res.status(400).send('Invalid template'); } ``` • Validate template input before passing it to `compile()`. Reject templates containing decorator syntax (`{{*...}}`) if decorators are not used in your application. • Use the pre-compilation workflow: compile templates at build time and serve only pre-compiled templates; do not call `compile()` at request time.

Related

Alias · CVE (1)

  • CVE-2026-33939 Handlebars provides the power necessary to let users build semantic templates. vulnerability

Weakness · CWE (1)

  • CWE-754 Improper Check for Unusual or Exceptional Conditions weakness

References