Repository navigation
build(deps-dev): Bump dependency handlebars to v4.7.10 [SECURITY] - #365
Open
renovate[bot] wants to merge 1 commit into
Open
renovate[bot] wants to merge 1 commit into
renovate[bot] wants to merge 1 commit into
Conversation
This branch has not been deployed
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.9→4.7.10Handlebars: JavaScript Injection via AST Type Confusion in compile (bypass of CVE-2026-33937)
CVE-2026-106446 / GHSA-8r5x-fm3f-whwj
More information
Details
Summary
Handlebars.compile()andHandlebars.precompile()accept a pre-parsed AST as well as a template string. Handlebars 4.7.9 added validation for such ASTs. It only checks values onPathExpression,NumberLiteralandBooleanLiteralnodes, and the compiler still writes several other AST values into the generated JavaScript unchecked.If an application passes an untrusted object to
compile()orprecompile(), such as a parsed JSON request body, that object can carry arbitrary JavaScript. Withcompile(), the code runs on the server when the template renders. Withprecompile(), it ends up in the precompiled output and runs wherever that output is loaded.Applications that only ever pass template strings are not affected.
This bypasses the AST validation added in 4.7.9 for GHSA-2w6w-674q-4c4q, GHSA-xhpv-hc6g-r9c6 and GHSA-3mfm-83xf-c92r.
Details
The 4.7.9 validator runs in
parseWithoutProcessing()and walks the whole AST. It only checks values on nodes whosetypeisPathExpression,NumberLiteralorBooleanLiteral. It passes over plain objects without atype, and over strings and other non-object values. The compiler reads these values from other places and writes them into the generated code as-is:Program.blockParams.lengthcontainer.program(<index>, data, <length>)depthon a param that is not aPathExpression, e.g. aStringLiteraldepths[<depth>]stringParams: trueStringLiteral.valuethat is not a stringstringParams: truePathExpression.originalthat is not a stringstringParams: trueThe first row works with default options. A
ProgramwithblockParams: { "length": "<JS expression>" }passes validation because:blockParamsobject has notype, so none of the type-specific checks apply, andlengthbecause it is not an object.The compiler then reads
program.blockParams.lengthand writes the string directly into the template function. Thecontainer.program(...)call is part of the helper options object, which is built before the helper is looked up. The code therefore runs on render even if the block's helper does not exist.Proof of Concept
poc.json.missingHelperdoes not need to exist:{ "text": { "type": "Program", "loc": { "start": { "line": 1, "column": 0 } }, "body": [ { "type": "BlockStatement", "path": { "type": "PathExpression", "data": false, "depth": 0, "parts": ["missingHelper"], "original": "missingHelper", "loc": { "start": { "line": 1, "column": 0 } } }, "params": [], "program": { "type": "Program", "blockParams": { "length": "(()=>{throw new Error('Injected code ran as uid ' + process.getuid())})()" }, "body": [], "loc": { "start": { "line": 1, "column": 0 } } }, "openStrip": { "open": false, "close": false }, "inverseStrip": { "open": false, "close": false }, "closeStrip": { "open": false, "close": false }, "loc": { "start": { "line": 1, "column": 0 } } } ] } }The server responds with HTTP 500 and an error page showing the injected code ran inside the Node.js process:
Impact
An application is affected if untrusted input can reach
Handlebars.compile()orHandlebars.precompile()as an object instead of a string. A common way this happens is passing a field from a JSON request body straight tocompile().compile(): arbitrary JavaScript runs in the Node.js process with the application's privileges (remote code execution).precompile(): the injected code is written into the precompiled template and runs wherever that template is loaded, for example in users' browsers.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.Credits
Variant
Program.blockParamsVariant
BooleanLiteral|NumberLiteral.valueVariant
PathExpression.depthSeverity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:HReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Handlebars: JavaScript Injection via Unsafe Inline Embedding of Precompiled Templates
CVE-2026-106444 / GHSA-xw65-4hp5-5hc7
More information
Details
Summary
Handlebars.precompile()generates JavaScript source that is commonly embedded in browser<script>elements. Before the fix, static template text containing</script>was emitted unchanged. HTML parsers recognize</script>even inside a JavaScript string literal, closing the surrounding script element and allowing following attacker-controlled markup to be parsed and executed.This affects applications that precompile attacker-controlled templates and embed the generated source directly in an HTML
<script>element. It does not affect ordinary server-side rendering or precompiled templates delivered as external JavaScript files.Details
Static text is serialized by
quotedString()inlib/handlebars/compiler/code-gen.js. The generated JavaScript is valid, but JavaScript quoting alone does not make it safe to embed in HTML. In HTML script data, the sequence</script>terminates the element regardless of JavaScript string context.On affected releases, this template:
could produce generated source containing:
When included inline in an HTML document, the first
</script>closes the script containing the precompiled template. The next<script>element is then parsed as HTML and executes.Proof of Concept
Affected versions print
true. Embeddingoutputdirectly in an inline<script>element allows the injected script tag to be parsed by the browser.Workarounds
Credits
Reported by Curly-Haired-Baboon Aka Laplas
Severity
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:L/A:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Handlebars: JavaScript Injection via Own Property Check Bypass
CVE-2026-106445 / GHSA-p8wg-vrv2-v86f
More information
Details
Summary
Handlebars can expose the
Functionconstructor despite its prototype-access deny list. When a template reachesFunction.prototype, its ownconstructorproperty is returned before the deny list is checked. An attacker who can render a controlled template withallowProtoMethodsByDefault: truecan inject and execute arbitrary JavaScript, leading to Remote Code Execution on the server.Description
lookupPropertytrusts own properties:Normally, prototype-derived values reach
resultIsAllowed, which blocks dangerous method names such asconstructor. However,constructoris itself an own property of prototype objects:As a result, once a template reaches
Function.prototype, looking upconstructorreturnsFunctionwithout consulting the deny list.Proof of Concept
An attacker needs to reach any prototype object where constructor is an own property, then access constructor to obtain Function. The shortest path requires only an accessible function in the template context:
Workarounds
Do not set
allowProtoMethodsByDefault: truewhen compiling untrusted templates with untrusted data.If you are using packages like hbs which set
allowProtoMethodsByDefault: trueby default, you have to update Handlebars to the latest version.Severity
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Release Notes
handlebars-lang/handlebars.js (handlebars)
v4.7.10Compare Source
f37c599812c226<!--and<scriptin precompiled output -609d1b1GHSA-xw65-4hp5-5hc7ceec388GHSA-p8wg-vrv2-v86fc28ee7a7d501a5703fdccGHSA-8r5x-fm3f-whwj0fcf25cea8ed82d069c1c6714e07Compatibility notes:
{{#each}}iterates iterables such asMap,Setand generators lazily, likefor...of, instead ofcopying them into an array first. Values added to the iterable while the block renders are now visited too.
Commits
Configuration
📅 Schedule: (UTC)
🚦 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.