{"id":"GHSA-442j-39wm-28r2","summary":"Handlebars.js has a Property Access Validation Bypass in container.lookup","details":"## Summary\n\nIn `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.\n\nOnly relevant when the **compat** compile option is enabled (`{compat: true}`), which activates `depthedLookup` in `lib/handlebars/compiler/javascript-compiler.js`.\n\n## Description\n\nThe vulnerable code in `lib/handlebars/runtime.js` (lines 137–144):\n\n```javascript\nlookup: function (depths, name) {\n  const len = depths.length;\n  for (let i = 0; i \u003c len; i++) {\n    let result = depths[i] && container.lookupProperty(depths[i], name);\n    if (result != null) {\n      return depths[i][name];  // BUG: should be `return result;`\n    }\n  }\n},\n```\n\n`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.\n\n## Workarounds\n\n- Avoid enabling `{ compat: true }` when rendering templates that include untrusted data.\n- Ensure context data objects are plain JSON (no Proxies, no getter-based accessor properties).","modified":"2026-03-30T18:29:15.982647Z","published":"2026-03-29T15:16:37Z","related":["CGA-2fhq-v3jc-pvc2"],"database_specific":{"severity":"LOW","github_reviewed_at":"2026-03-29T15:16:37Z","cwe_ids":["CWE-367"],"github_reviewed":true,"nvd_published_at":null},"references":[{"type":"WEB","url":"https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-442j-39wm-28r2"},{"type":"WEB","url":"https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2"},{"type":"PACKAGE","url":"https://github.com/handlebars-lang/handlebars.js"},{"type":"WEB","url":"https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9"}],"affected":[{"package":{"name":"handlebars","ecosystem":"npm","purl":"pkg:npm/handlebars"},"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":"\u003c= 4.7.8"}}],"schema_version":"1.7.5","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N"}]}