{"id":"GHSA-xw65-4hp5-5hc7","summary":"Handlebars: JavaScript Injection via Unsafe Inline Embedding of Precompiled Templates","details":"## Summary\n\n`Handlebars.precompile()` generates JavaScript source that is commonly embedded in browser `\u003cscript\u003e` elements. Before the fix, static template text containing `\u003c/script\u003e` was emitted unchanged. HTML parsers recognize `\u003c/script\u003e` even inside a JavaScript string literal, closing the surrounding script element and allowing following attacker-controlled markup to be parsed and executed.\n\nThis affects applications that precompile attacker-controlled templates and embed the generated source directly in an HTML `\u003cscript\u003e` element. It does not affect ordinary server-side rendering or precompiled templates delivered as external JavaScript files.\n\n## Details\n\nStatic text is serialized by `quotedString()` in `lib/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 `\u003c/script\u003e` terminates the element regardless of JavaScript string context.\n\nOn affected releases, this template:\n\n```handlebars\nsafe\u003c/script\u003e\u003cscript\u003ealert(\"XSS\")\u003c/script\u003e\u003cscript\u003e\n```\n\ncould produce generated source containing:\n\n```js\nreturn 'safe\u003c/script\u003e\u003cscript\u003ealert(\"XSS\")\u003c/script\u003e\u003cscript\u003e';\n```\n\nWhen included inline in an HTML document, the first `\u003c/script\u003e` closes the script containing the precompiled template. The next `\u003cscript\u003e` element is then parsed as HTML and executes.\n\n## Proof of Concept\n\n```js\nconst Handlebars = require('handlebars');\n\nconst template = 'safe\u003c/script\u003e\u003cscript\u003ealert(\"XSS\")\u003c/script\u003e\u003cscript\u003e';\nconst output = Handlebars.precompile(template);\n\nconsole.log(output.includes('\u003c/script\u003e'));\n```\n\nAffected versions print `true`. Embedding `output` directly in an inline `\u003cscript\u003e` element allows the injected script tag to be parsed by the browser.\n\n## Workarounds\n\n- Do not inline precompiled output from untrusted templates into HTML documents.\n- Serve generated precompiled templates as external JavaScript files where practical.\n\n## Credits\n\nReported by Curly-Haired-Baboon Aka Laplas","aliases":["CVE-2026-106444"],"modified":"2026-10-08T18:00:09.713255773Z","published":"2026-10-08T17:52:37Z","database_specific":{"severity":"MODERATE","github_reviewed":true,"github_reviewed_at":"2026-10-08T17:52:37Z","nvd_published_at":"2026-10-06T20:17:26Z","cwe_ids":["CWE-116"]},"references":[{"type":"WEB","url":"https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-xw65-4hp5-5hc7"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-106444"},{"type":"WEB","url":"https://github.com/handlebars-lang/handlebars.js/pull/2185"},{"type":"WEB","url":"https://github.com/handlebars-lang/handlebars.js/commit/609d1b11c833c9a3e00f56f2f34d22f425446725"},{"type":"PACKAGE","url":"https://github.com/handlebars-lang/handlebars.js"},{"type":"WEB","url":"https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.10"}],"affected":[{"package":{"name":"handlebars","ecosystem":"npm","purl":"pkg:npm/handlebars"},"ranges":[{"type":"SEMVER","events":[{"introduced":"4.0.0"},{"fixed":"4.7.10"}]}],"database_specific":{"last_known_affected_version_range":"\u003c= 4.7.9","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-xw65-4hp5-5hc7/GHSA-xw65-4hp5-5hc7.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:L/A:N"}]}