CVE-2026-33916
MEDIUMVulnerability Assessment
| Weakness |
CWE
OWASP Top 10:2025
A05:2025 - Injection
ASVS 5.0
V1 - Encoding and Sanitization Output encoding, context-aware escaping
MITRE ATT&CK
2 techniques across 2 tactics: Initial Access, Execution The technique list with ATT&CK links and the kill-chain view is part of the Basic plan and up. |
| Impact | The CVSS score of 4.7 (Medium, CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:L/A:N) reflects moderate severity: the attack vector is network-accessible and unauthenticated, but attack complexity is high and user interaction is required. The scope is changed (server-rendered output affects client context), and impact is limited to confidentiality and integrity (no availability impact). However, real-world risk depends heavily on the presence of a separate prototype pollution vulnerability in the target application-this is not a direct remote code execution vector but rather a secondary exploitation technique. The proof-of-concept code exists and is publicly available, confirming reproducibility. No CISA KEV status is indicated in the input data, meaning active exploitation in the wild has not been confirmed at the time of analysis. The combination of high attack complexity (requires both prototype pollution and template knowledge), user interaction requirement (reflected XSS variant), and the need for a precursor vulnerability suggests this is a lower-priority issue than the CVSS score alone implies, though applications using Handlebars in combination with known prototype pollution sinks (qs, minimist, etc.) should be prioritized for patching. Organizations should weigh this against their specific dependency landscape. |
| Exploit ScenarioDerived | An attacker identifies that a web application uses Handlebars templates with a partial named 'widget' and discovers a prototype pollution vulnerability in the application's use of the qs library for query string parsing. The attacker crafts a malicious URL containing ?widget=<img src=x onerror="alert(document.domain)"> which is parsed by qs, polluting Object.prototype. When the application renders its Handlebars template containing {{> widget}}, the resolvePartial() function retrieves the polluted Object.prototype.widget string instead of the intended partial template, and the unescaped HTML payload is rendered to the victim's browser, executing the JavaScript and stealing session cookies or performing account takeover. This requires user interaction (the victim must click the malicious link) and knowledge or guessing of partial names, but no authentication and only network access. |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – Mar 26, 2026
Handlebars template engine fails to guard prototype-chain access when resolving partial templates, allowing unauthenticated remote attackers to inject unescaped HTML and JavaScript through prototype pollution. When Object.prototype is polluted with a string value matching a partial name referenced in a template, the malicious string is rendered without HTML escaping, resulting in reflected or stored XSS. Exploitation requires a separate prototype pollution vulnerability in the target application (such as via qs or minimist libraries) combined with knowledge of partial names used in templates; publicly available proof-of-concept code demonstrates the attack. The vulnerability affects npm package handlebars (pkg:npm/handlebars) across multiple versions and is distinct from earlier prototype-access issues CVE-2021-23369 and CVE-2021-23383.
RemediationAI
Upgrade handlebars to version 4.7.9 or later immediately (see vendor advisory at https://github.com/handlebars-lang/handlebars.js/security/advisories/GHSA-2qvq-rjwj-gvw9 and release notes at https://github.com/handlebars-lang/handlebars.js/releases/tag/v4.7.9). This release includes the fix commit 68d8df5a88e0a26fe9e6084c5c6aaebe67b07da2 that guards partial resolution against prototype-chain traversal. Until patching is possible, apply Object.freeze(Object.prototype) early in application startup to prevent prototype pollution, though this is a temporary mitigation and may cause compatibility issues with other libraries. Additionally, audit all dependencies for prototype pollution vulnerabilities (particularly qs, minimist, and other querystring/JSON parsing libraries) and upgrade or replace those packages. For defense-in-depth, use Content Security Policy (CSP) headers to restrict script execution and validate all data sources before template rendering. Consider using the Handlebars runtime-only build (handlebars/runtime) if your application does not require dynamic template compilation, reducing attack surface.
Affected Packages
Source: OSV (Open Source Vulnerabilities)
Affects your stack
Affects 1 package in npm
Checking this CVE against your own stacks and servers is part of the Basic plan and up.
Technical ContextAI · show details
Handlebars is a popular JavaScript templating engine (npm package: pkg:npm/handlebars) that supports partial template inclusion via the {{> partial_name}} syntax. The vulnerability resides in the resolvePartial() and invokePartial() functions in lib/handlebars/runtime.js, which perform property lookup on options.partials using plain bracket notation without checking hasOwnProperty(). This allows traversal of the JavaScript prototype chain-specifically Object.prototype-to resolve partial names. The root cause is classified under CWE-79 (Cross-site Scripting) and represents a case of unsafe prototype chain traversal combined with missing output encoding. When a polluted Object.prototype property matches a partial reference in a template, the string value is retrieved and inserted into the rendered output without HTML entity encoding, bypassing the security model that should isolate data from template logic.
Know when the next one hits your stack
- Watch products and get an email when something new is published
- Check this CVE against your own stack and servers
- Exploit and PoC references, threat intelligence from 22 sources
No credit card · 7-day full trial
Severity by source
AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:L/A:N
Primary rating from NVD.
CVSS VectorNVD
Lifecycle Timeline
2DescriptionNVD
Summary
resolvePartial() in the Handlebars runtime resolves partial names via a plain property lookup on options.partials without guarding against prototype-chain traversal. When Object.prototype has been polluted with a string value whose key matches a partial reference in a template, the polluted string is used as the partial body and rendered without HTML escaping, resulting in reflected or stored XSS.
Description
The root cause is in lib/handlebars/runtime.js inside resolvePartial() and invokePartial():
// Vulnerable: plain bracket access traverses Object.prototype
partial = options.partials[options.name];hasOwnProperty is never checked, so if Object.prototype has been seeded with a key whose name matches a partial reference in the template (e.g. widget), the lookup succeeds and the polluted string is returned. The runtime emits a prototype-access warning, but the partial is still resolved and its content is inserted into the rendered output unescaped. This contradicts the documented security model and is distinct from CVE-2021-23369 and CVE-2021-23383, which addressed data property access rather than partial template resolution.
Prerequisites for exploitation:
- The target application must be vulnerable to prototype pollution (e.g. via
qs,minimist, or
any querystring/JSON merge sink).
- The attacker must know or guess the name of a partial reference used in a template.
Proof of Concept
const Handlebars = require('handlebars');
// Step 1: Prototype pollution (via qs, minimist, or another vector)
Object.prototype.widget = '<img src=x onerror="alert(document.domain)">';
// Step 2: Normal template that references a partial
const template = Handlebars.compile('<div>Welcome! {{> widget}}</div>');
// Step 3: Render - XSS payload injected unescaped
const output = template({});
// Output: <div>Welcome! <img src=x onerror="alert(document.domain)"></div>> The runtime prints a prototype access warning claiming "access has been denied," but the partial still resolves and returns the polluted value.
Workarounds
- Apply
Object.freeze(Object.prototype)early in application startup to prevent prototype pollution. Note: this may break other libraries. - Use the Handlebars runtime-only build (
handlebars/runtime), which does not compile templates and reduces the attack surface.
Blast Radius
ecosystem impact- 3 npm packages depend on handlebars (1 direct, 2 indirect)
Ecosystem-wide dependent count for version 4.0.0.
Executive ViewAI
CVE-2026-33916 presents moderate security risk, a cross-site scripting vulnerability rated CVSS 4.7. Attackers could inject scripts to steal sessions or perform actions as authenticated users. A patch is available and should be applied during regular vulnerability management.
Apply vendor patch. If patching is delayed: implement CSP headers, enable HttpOnly cookies, deploy WAF XSS rules.
Threat Intelligence Overview
How this decision was reached
The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.
What every action level means
SSVC AssessmentENISA
Priority Score
Attack Technique
Cross-Site Scripting occurs when an application accepts untrusted data and sends it to a web browser without proper validation or encoding.
NVD
CVE.org
EPSS
Vulnrichment
GitHub
VulDB
Exploit-DB