GHSA-XW65-4HP5-5HC7
Vulnerability from github – Published: 2026-10-08 17:52 – Updated: 2026-10-08 17:52Summary
Handlebars.precompile() generates JavaScript source that is commonly embedded in browser <script> elements. Before the fix, static template text containing </script> was emitted unchanged. HTML parsers recognize </script> even inside a JavaScript string literal, closing the surrounding script element and allowing following attacker-controlled markup to be parsed and executed.
This affects applications that precompile attacker-controlled templates and embed the generated source directly in an HTML <script> element. It does not affect ordinary server-side rendering or precompiled templates delivered as external JavaScript files.
Details
Static 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 </script> terminates the element regardless of JavaScript string context.
On affected releases, this template:
safe</script><script>alert("XSS")</script><script>
could produce generated source containing:
return 'safe</script><script>alert("XSS")</script><script>';
When included inline in an HTML document, the first </script> closes the script containing the precompiled template. The next <script> element is then parsed as HTML and executes.
Proof of Concept
const Handlebars = require('handlebars');
const template = 'safe</script><script>alert("XSS")</script><script>';
const output = Handlebars.precompile(template);
console.log(output.includes('</script>'));
Affected versions print true. Embedding output directly in an inline <script> element allows the injected script tag to be parsed by the browser.
Workarounds
- Do not inline precompiled output from untrusted templates into HTML documents.
- Serve generated precompiled templates as external JavaScript files where practical.
Credits
Reported by Curly-Haired-Baboon Aka Laplas
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.7.9"
},
"package": {
"ecosystem": "npm",
"name": "handlebars"
},
"ranges": [
{
"events": [
{
"introduced": "4.0.0"
},
{
"fixed": "4.7.10"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-106444"
],
"database_specific": {
"cwe_ids": [
"CWE-116"
],
"github_reviewed": true,
"github_reviewed_at": "2026-10-08T17:52:37Z",
"nvd_published_at": "2026-10-06T20:17:26Z",
"severity": "MODERATE"
},
"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 \u0027safe\u003c/script\u003e\u003cscript\u003ealert(\"XSS\")\u003c/script\u003e\u003cscript\u003e\u0027;\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(\u0027handlebars\u0027);\n\nconst template = \u0027safe\u003c/script\u003e\u003cscript\u003ealert(\"XSS\")\u003c/script\u003e\u003cscript\u003e\u0027;\nconst output = Handlebars.precompile(template);\n\nconsole.log(output.includes(\u0027\u003c/script\u003e\u0027));\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",
"id": "GHSA-xw65-4hp5-5hc7",
"modified": "2026-10-08T17:52:37Z",
"published": "2026-10-08T17:52:37Z",
"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"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "Handlebars: JavaScript Injection via Unsafe Inline Embedding of Precompiled Templates"
}
Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline
Sightings and recorded dates, grouped by day · UTC
Loading timeline…
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.