Skip to content

Update dependency handlebars to v4.7.9 [SECURITY]#27000

Open
renovate[bot] wants to merge 1 commit intomainfrom
renovate/npm-handlebars-vulnerability
Open

Update dependency handlebars to v4.7.9 [SECURITY]#27000
renovate[bot] wants to merge 1 commit intomainfrom
renovate/npm-handlebars-vulnerability

Conversation

@renovate
Copy link
Copy Markdown
Contributor

@renovate renovate bot commented Mar 27, 2026

This PR contains the following updates:

Package Change Age Confidence
handlebars (source) 4.7.84.7.9 age confidence

GitHub Vulnerability Alerts

CVE-2026-33916

Summary

resolvePartial() in the Handlebars runtime resolves partial names via a plain property lookup on options.partials without guarding against prototype-chain traversal. When Object.prototype has 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.js inside resolvePartial() and invokePartial():

// Vulnerable: plain bracket access traverses Object.prototype
partial = options.partials[options.name];

hasOwnProperty is never checked, so if Object.prototype has 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:

  1. The target application must be vulnerable to prototype pollution (e.g. via qs, minimist, or
    any querystring/JSON merge sink).
  2. The attacker must know or guess the name of a partial reference used in a template.

Proof of Concept

const Handlebars = require('handlebars');

// Step 1: Prototype pollution (via qs, minimist, or another vector)
Object.prototype.widget = '<img src=x onerror="alert(document.domain)">';

// Step 2: Normal template that references a partial
const template = Handlebars.compile('<div>Welcome! {{> widget}}</div>');

// Step 3: Render — XSS payload injected unescaped
const output = template({});
// Output: <div>Welcome! <img src=x onerror="alert(document.domain)"></div>

The runtime prints a prototype access warning claiming "access has been denied," but the partial still resolves and returns the polluted value.

Workarounds

  • Apply Object.freeze(Object.prototype) early in application startup to prevent prototype pollution. Note: this may break other libraries.
  • Use the Handlebars runtime-only build (handlebars/runtime), which does not compile templates and reduces the attack surface.

Release Notes

handlebars-lang/handlebars.js (handlebars)

v4.7.9

Compare Source


Configuration

📅 Schedule: Branch creation - "" in timezone Etc/UTC, Automerge - Only on Sunday and Saturday ( * * * * 0,6 ), Between 12:00 AM and 12:59 PM, only on Monday ( * 0-12 * * 1 ) in timezone Etc/UTC.

🚦 Automerge: Enabled.

Rebasing: Never, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@github-actions github-actions bot added the dependencies Pull requests that update a dependency file label Mar 27, 2026
@sonarqubecloud
Copy link
Copy Markdown

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 27, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 73.19%. Comparing base (e494949) to head (a3ba5d1).
⚠️ Report is 14 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #27000      +/-   ##
==========================================
- Coverage   73.21%   73.19%   -0.02%     
==========================================
  Files        1539     1540       +1     
  Lines      121718   121774      +56     
  Branches    14733    14711      -22     
==========================================
+ Hits        89118    89137      +19     
- Misses      31568    31606      +38     
+ Partials     1032     1031       -1     
Flag Coverage Δ
admin-tests 54.35% <ø> (ø)
e2e-tests 73.19% <ø> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants