fix(deps): update dependency handlebars to v4.7.9 [security]#224
Open
renovate[bot] wants to merge 1 commit intomainfrom
Open
fix(deps): update dependency handlebars to v4.7.9 [security]#224renovate[bot] wants to merge 1 commit intomainfrom
renovate[bot] wants to merge 1 commit intomainfrom
Conversation
|
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-33916
Summary
resolvePartial()in the Handlebars runtime resolves partial names via a plain property lookup onoptions.partialswithout guarding against prototype-chain traversal. WhenObject.prototypehas been polluted with a string value whose key matches a partial reference in a template, the polluted string is used as the partial body and rendered without HTML escaping, resulting in reflected or stored XSS.Description
The root cause is in
lib/handlebars/runtime.jsinsideresolvePartial()andinvokePartial():hasOwnPropertyis never checked, so ifObject.prototypehas been seeded with a key whose name matches a partial reference in the template (e.g.widget), the lookup succeeds and the polluted string is returned. The runtime emits a prototype-access warning, but the partial is still resolved and its content is inserted into the rendered output unescaped. This contradicts the documented security model and is distinct from CVE-2021-23369 and CVE-2021-23383, which addressed data property access rather than partial template resolution.Prerequisites for exploitation:
qs,minimist, orany querystring/JSON merge sink).
Proof of Concept
Workarounds
Object.freeze(Object.prototype)early in application startup to prevent prototype pollution. Note: this may break other libraries.handlebars/runtime), which does not compile templates and reduces the attack surface.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.).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-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.Release Notes
handlebars-lang/handlebars.js (handlebars)
v4.7.9Compare Source
e0137c2eab1d14hashto be aRecord<string, any>-de4414d4512766e497a3568d8df5Commits
Configuration
📅 Schedule: Branch creation - "" in timezone Europe/Istanbul, Automerge - At any time (no schedule defined).
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, 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.