GHSA-442j-39wm-28r2

Suggest an improvement
Source
https://github.com/advisories/GHSA-442j-39wm-28r2
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/03/GHSA-442j-39wm-28r2/GHSA-442j-39wm-28r2.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-442j-39wm-28r2
Downstream
Related
Published
2026-03-29T15:16:37Z
Modified
2026-03-30T18:29:15.982647Z
Severity
  • 3.7 (Low) CVSS_V3 - CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N CVSS Calculator
Summary
Handlebars.js has a Property Access Validation Bypass in container.lookup
Details

Summary

In lib/handlebars/runtime.js, the container.lookup() function uses container.lookupProperty() as a gate check to enforce prototype-access controls, but then discards the validated result and performs a second, unguarded property access (depths[i][name]). This Time-of-Check Time-of-Use (TOCTOU) pattern means the security check and the actual read are decoupled, and the raw access bypasses any sanitization that lookupProperty may perform.

Only relevant when the compat compile option is enabled ({compat: true}), which activates depthedLookup in lib/handlebars/compiler/javascript-compiler.js.

Description

The vulnerable code in lib/handlebars/runtime.js (lines 137–144):

lookup: function (depths, name) {
  const len = depths.length;
  for (let i = 0; i < len; i++) {
    let result = depths[i] && container.lookupProperty(depths[i], name);
    if (result != null) {
      return depths[i][name];  // BUG: should be `return result;`
    }
  }
},

container.lookupProperty() (lines 119–136) enforces hasOwnProperty checks and resultIsAllowed() prototype-access controls. However, container.lookup() only uses lookupProperty as a boolean gate — if the gate passes (result != null), it then performs an independent, raw depths[i][name] access that circumvents any transformation or wrapped value that lookupProperty may have returned.

Workarounds

  • Avoid enabling { compat: true } when rendering templates that include untrusted data.
  • Ensure context data objects are plain JSON (no Proxies, no getter-based accessor properties).
Database specific
{
    "severity": "LOW",
    "cwe_ids": [
        "CWE-367"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-03-29T15:16:37Z",
    "nvd_published_at": null
}
References

Affected packages

npm / handlebars

Package

Affected ranges

Type
SEMVER
Events
Introduced
4.0.0
Fixed
4.7.9

Database specific

source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/03/GHSA-442j-39wm-28r2/GHSA-442j-39wm-28r2.json"
last_known_affected_version_range
"<= 4.7.8"