chore: update dependency handlebars to v4.7.9 [security]#714
Open
renovate[bot] wants to merge 1 commit intomasterfrom
Open
chore: update dependency handlebars to v4.7.9 [security]#714renovate[bot] wants to merge 1 commit intomasterfrom
renovate[bot] wants to merge 1 commit intomasterfrom
Conversation
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
4.7.8→4.7.9GitHub Vulnerability Alerts
CVE-2026-33937
Summary
Handlebars.compile()accepts a pre-parsed AST object in addition to a template string. Thevaluefield of aNumberLiteralAST node is emitted directly into the generated JavaScript without quoting or sanitization. An attacker who can supply a crafted AST tocompile()can therefore inject and execute arbitrary JavaScript, leading to Remote Code Execution on the server.Description
Handlebars.compile()accepts either a template string or a pre-parsed AST. When an AST is supplied, the JavaScript code generator inlib/handlebars/compiler/javascript-compiler.jsemitsNumberLiteralvalues verbatim:Because the value is not wrapped in quotes or otherwise sanitized, passing a string such as
{},{})) + process.getBuiltinModule('child_process').execFileSync('id').toString() //as thevalueof aNumberLiteralcauses the generatedeval-ed code to break out of its intended context and execute arbitrary commands.Any endpoint that deserializes user-controlled JSON and passes the result directly to
Handlebars.compile()is exploitable.Proof of Concept
Server-side Express application that passes
req.body.texttoHandlebars.compile():The response body will contain the output of the
idcommand executed on the server.Workarounds
Handlebars.compile(): ensure the argument is always astring, never a plain object or JSON-deserialized value.handlebars/runtime) on the server if templates are pre-compiled at build time;compile()will be unavailable.CVE-2026-33938
Summary
The
@partial-blockspecial 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-blockwith 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-blockin thedataframe that is accessible to templates. In nested contexts, a parent frame's@partial-blockis 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-blockwith an attacker-controlled value.When
{{> @​partial-block}}is subsequently evaluated,invokePartialreceives the crafted object. The runtime, finding an object that is not a compiled function, falls back to dynamically compiling the value viaenv.compile(). If that value is a well-formed Handlebars AST containing injected code, the injected JavaScript runs in the server process.The
handlebars-helpersnpm package (commonly used with Handlebars) includes several helpers such asmergethat can be used as the mutation primitive.Proof of Concept
Tested with Handlebars 4.7.8 and
handlebars-helpers:Workarounds
require('handlebars/runtime')). Thecompile()method is absent, eliminating the vulnerable fallback path.handlebars-helpers) in contexts where templates or context data can be influenced by untrusted input.CVE-2026-33939
Summary
When a Handlebars template contains decorator syntax referencing an unregistered decorator (e.g.
{{*n}}), the compiled template callslookupProperty(decorators, "n"), which returnsundefined. The runtime then immediately invokes the result as a function, causing an unhandledTypeError: ... is not a functionthat crashes the Node.js process. Any application that compiles user-supplied templates without wrapping the call in atry/catchis 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:When
"n"is not a registered decorator,lookupProperty(decorators, "n")returnsundefined. The expression immediately attempts to callundefinedas a function, producing: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 callsHandlebars.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
Expected crash output:
Workarounds
try/catch:compile(). Reject templates containing decorator syntax ({{*...}}) if decorators are not used in your application.compile()at request time.CVE-2026-33940
Summary
A crafted object placed in the template context can bypass all conditional guards in
resolvePartial()and causeinvokePartial()to returnundefined. The Handlebars runtime then treats the unresolved partial as a source that needs to be compiled, passing the crafted object toenv.compile(). Because the object is a valid Handlebars AST containing injected code, the generated JavaScript executes arbitrary commands on the server. The attack requires the adversary to control a value that can be returned by a dynamic partial lookup.Description
The vulnerable code path spans two functions in
lib/handlebars/runtime.js:resolvePartial(): A crafted object withcall: truesatisfies the first branch condition (partial.call) and causes an early return of the original object itself, because none of the remaining conditionals (string check,options.partialslookup, etc.) match a plain object. The function returns the crafted object as-is.invokePartial(): WhenresolvePartialreturns a non-function object,invokePartialproducesundefined. The runtime interpretsundefinedas "partial not yet compiled" and callsenv.compile(partial, ...)wherepartialis the crafted AST object. The JavaScript code generator processes the AST and emits JavaScript containing the injected payload, which is then evaluated.Minimum prerequisites:
{{> (lookup . "key")}}or equivalent.In server-side rendering scenarios where templates process user-supplied context data, this enables full Remote Code Execution.
Proof of Concept
Workarounds
require('handlebars/runtime')). Withoutcompile(), the fallback compilation path ininvokePartialis unreachable.{{> (lookup ...)}}) when context data is user-controlled.CVE-2026-33941
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.jsgenerates JavaScript source by string-interpolating several values directly into the output. Four distinct injection points exist:1. Template name injection
template.nameis 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)opts.namespaceis emitted as raw JavaScript. Anything after a;in the value becomes an additional JavaScript statement.3. CommonJS path injection (
-c/--commonjs)opts.commonjsis interpolated inside double quotes with no escaping, allowing"to close the string and inject further code.4. AMD path injection (
-h/--handlebarPath)opts.handlebarPathis 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
pwnedon disk):Namespace vector:
CommonJS vector:
AMD vector:
Workarounds
",',;, etc.).Release Notes
handlebars-lang/handlebars.js (handlebars)
v4.7.9Compare Source
e0137c2eab1d14hashto be aRecord<string, any>-de4414d4512766e497a3568d8df5Commits
Configuration
📅 Schedule: Branch creation - "" (UTC), Automerge - At any time (no schedule defined).
🚦 Automerge: Enabled.
♻ Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.