CVE-2019-19919
Critical · 9.8CVSS
9.8
EPSS
7.1%
Published
Dec 20, 2019
CISA due date
—
Cloudanix analysis
Some applications using older Handlebars software can be tricked into running attacker commands if they process templates supplied by untrusted users.
- Exploitation
- Remote Unauthenticated
- Attacker needs
- None
- Complexity
- Low
- Impact
- Remote Code Execution
- Component
- Library
- Class
- Improper Input Validation
- Remediation
- Upgrade
- Effort
- Medium
- Patch risk
- Low
What it actually does
CVE-2019-19919 affects Handlebars versions prior to 4.3.0 and allows prototype pollution through unsafe handling of template-controlled properties such as __proto__ and __defineGetter__. If an attacker can supply or influence a Handlebars template or template input in an application that compiles or renders untrusted templates, they may modify JavaScript object prototypes and influence downstream property lookups. In vulnerable usage patterns, this can be chained to arbitrary JavaScript execution in the Node.js process, resulting in remote code execution with the privileges of the affected application.
Why it matters to the business
Successful exploitation can allow an unauthenticated remote attacker to run code on servers that process attacker-controlled Handlebars templates, potentially leading to application takeover, data theft, service disruption, credential exposure, and lateral movement from the compromised runtime. Although this issue is not listed in CISA KEV and the provided exploit maturity is none, the vulnerability is high severity and affects a widely used JavaScript templating library that may be embedded in many downstream applications, including products that bundle Handlebars such as Tenable.sc.
How an attack unfolds
An attacker first identifies an application or product path that uses a vulnerable Handlebars version and accepts template content, template partials, helper definitions, or otherwise attacker-influenced values that are compiled or rendered by Handlebars. The attacker submits a crafted payload that references special JavaScript object properties such as __proto__ or __defineGetter__ to pollute Object.prototype or alter getter behavior. Once the runtime's prototype chain is modified, subsequent application logic may resolve attacker-controlled properties or execute attacker-influenced functions. In vulnerable configurations, the attacker can use this primitive to escape intended template restrictions and trigger arbitrary JavaScript execution in the server-side Node.js process. The impact depends heavily on whether the application exposes untrusted template rendering; applications that only render trusted, static templates are significantly less exposed.
How to fix it
Upgrade Handlebars to version 4.3.0 or later wherever it is used directly or bundled transitively. Because this is a library vulnerability, review package-lock.json, yarn.lock, pnpm-lock.yaml, npm-shrinkwrap.json, and container images to identify transitive or vendored copies of handlebars. If an affected commercial product bundles Handlebars, apply the vendor-supplied fixed release or security patch rather than attempting to replace the embedded library manually. As defense in depth, do not compile or render untrusted Handlebars templates; treat user-provided templates, report definitions, email templates, and plugin-supplied templates as code. Restrict or disable user-controlled helpers, sandbox template execution where possible, run Node.js services with least privilege, and prevent template rendering processes from accessing secrets or sensitive filesystem paths unnecessarily.
How to confirm the fix worked
Confirm all deployed applications and build artifacts use Handlebars 4.3.0 or later by checking package manifests and lockfiles with commands such as npm ls handlebars, yarn why handlebars, pnpm why handlebars, and software composition analysis tools. Inspect container images and deployed bundles for embedded node_modules/handlebars/package.json files showing versions prior to 4.3.0. Exercise any features that accept user-supplied templates and verify they are disabled, restricted to trusted users, or rendered in a hardened sandbox. Run dependency scanning in CI/CD and against production images to ensure no vulnerable transitive dependency remains. For vendor appliances or bundled products, verify the installed version matches the vendor advisory for a fixed release.
Typical attack path
- Identify a web application, API, build system, reporting feature, email templating feature, plugin system, or bundled product that uses Handlebars prior to 4.3.0.
- Find an input path where the attacker can control template content, partials, helpers, or data that is compiled or interpreted as a Handlebars template.
- Submit a crafted Handlebars payload using prototype-related properties such as __proto__ or __defineGetter__.
- Pollute JavaScript object prototypes or alter getter behavior within the Node.js runtime.
- Chain the polluted prototype state into template evaluation or application logic to execute arbitrary JavaScript.
- Use code execution to read sensitive files or environment variables, modify application behavior, deploy a web shell or backdoor, or pivot to additional systems.
How to detect it
To determine whether exploitation already occurred, review application access logs, API gateway logs, reverse proxy logs, WAF events, and request bodies for Handlebars expressions containing prototype-pollution or JavaScript execution primitives. Look for strings such as __proto__, __defineGetter__, constructor, prototype, lookup, with, blockHelperMissing, and suspicious nested Handlebars syntax in parameters that normally contain templates, report definitions, email bodies, or JSON configuration. On affected Node.js servers, review process telemetry and EDR logs for unexpected child processes spawned by node, including sh, bash, dash, cmd.exe, powershell.exe, curl, wget, nc, ncat, python, perl, or node subprocesses. Inspect application logs for template compilation errors, unusual helper resolution failures, TypeError or ReferenceError messages involving prototype properties, and crashes around Handlebars rendering. Review filesystem changes for newly created scripts, web-accessible files, modified package files, or persistence artifacts written by the Node.js service account. If telemetry is available, correlate suspicious template requests with outbound network connections, DNS lookups, credential access, environment variable dumping, or reads of sensitive files such as .env, configuration files, SSH keys, or cloud credential files. Because there are no universally unique exploit artifacts for this library issue, detection should focus on suspicious template payloads plus post-exploitation behavior from the Node.js process.
- __proto__
- __defineGetter__
- constructor.prototype
- Object.prototype
- {{__proto__
- {{#with
- {{#lookup
- blockHelperMissing
- Handlebars.compile
- Handlebars.precompile
- node_modules/handlebars/package.json
- node_modules/handlebars/dist/handlebars.js
- node_modules/handlebars/lib/handlebars
- node_modules/handlebars/package.json: "version": "4.0
- node_modules/handlebars/package.json: "version": "4.1
- node_modules/handlebars/package.json: "version": "4.2
- node child process: /bin/sh
- node child process: /bin/bash
- node child process: cmd.exe
- node child process: powershell.exe
What your security team should do
- Inventory all applications, services, containers, serverless functions, CI jobs, and vendor products that include Handlebars, prioritizing internet-facing systems and features that render user-controlled templates.
- Upgrade Handlebars to 4.3.0 or later, or apply the relevant vendor patch for products that bundle the library.
- Search source code for server-side template compilation of untrusted input, especially use of Handlebars.compile, Handlebars.precompile, dynamic partials, custom helpers, and user-editable template features.
- Block or tightly restrict user-provided templates; where business requirements require them, isolate rendering in a sandboxed process with minimal privileges and no access to production secrets.
- Add dependency-scanning gates to CI/CD to prevent reintroduction of handlebars versions prior to 4.3.0.
- Review logs and telemetry for suspicious template payloads, prototype pollution strings, unexpected child process execution from Node.js services, and abnormal outbound connections.
- Rotate credentials and secrets accessible to any Node.js service where exploitation is suspected, because successful exploitation may expose environment variables and local configuration files.
The record
Versions of handlebars prior to 4.3.0 are vulnerable to Prototype Pollution leading to Remote Code Execution. Templates may alter an Object's __proto__ and __defineGetter__ properties, which may allow an attacker to execute arbitrary code through crafted payloads.
Affected packages
| Ecosystem | Package | Introduced | Fixed |
|---|---|---|---|
| RubyGems | bootstrap-wysihtml5-rails | 0.3.3.5 | No fix |
| npm | handlebars | 0 | 3.0.8 |
| npm | handlebars | 4.0.0 | 4.3.0 |
| Chainguard | code-server | 0 | 0 |
| Chainguard | code-server-compat | 0 | 0 |
| Chainguard | gitlab-rails-ce-18.1 | 0 | 0 |
| Chainguard | gitlab-rails-ce-18.2 | 0 | 0 |
| Chainguard | gitlab-rails-ce-18.3 | 0 | 0 |
| Chainguard | gitlab-rails-ce-18.4 | 0 | 0 |
| Chainguard | gitlab-rails-ce-18.5 | 0 | 0 |
| Chainguard | gitlab-rails-ce-18.6 | 0 | 0 |
| Chainguard | gitlab-rails-ce-18.7 | 0 | 0 |
| Chainguard | gitlab-rails-ce-assets-18.1 | 0 | 0 |
| Chainguard | gitlab-rails-ce-assets-18.2 | 0 | 0 |
| Chainguard | gitlab-rails-ce-assets-18.3 | 0 | 0 |
| Chainguard | gitlab-rails-ce-assets-18.4 | 0 | 0 |
| Chainguard | gitlab-rails-ce-assets-18.5 | 0 | 0 |
| Chainguard | gitlab-rails-ce-assets-18.6 | 0 | 0 |
| Chainguard | gitlab-rails-ce-assets-18.7 | 0 | 0 |
| Chainguard | gitlab-rails-ce-assets-18.8 | 0 | 0 |
| Chainguard | gitlab-rails-ce-assets-18.9 | 0 | 0 |
| Chainguard | gitlab-rails-ce-assets-fips-18.1 | 0 | 0 |
| Chainguard | gitlab-rails-ce-assets-fips-18.2 | 0 | 0 |
| Chainguard | gitlab-rails-ce-assets-fips-18.3 | 0 | 0 |
| Chainguard | gitlab-rails-ce-assets-fips-18.4 | 0 | 0 |
| Chainguard | gitlab-rails-ce-assets-fips-18.5 | 0 | 0 |
| Chainguard | gitlab-rails-ce-assets-fips-18.6 | 0 | 0 |
| Chainguard | gitlab-rails-ce-assets-fips-18.7 | 0 | 0 |
| Chainguard | gitlab-rails-ce-assets-fips-18.8 | 0 | 0 |
| Chainguard | gitlab-rails-ce-assets-fips-18.9 | 0 | 0 |
| Chainguard | gitlab-rails-ce-doc-18.1 | 0 | 0 |
| Chainguard | gitlab-rails-ce-doc-18.2 | 0 | 0 |
| Chainguard | gitlab-rails-ce-doc-18.3 | 0 | 0 |
| Chainguard | gitlab-rails-ce-doc-18.4 | 0 | 0 |
| Chainguard | gitlab-rails-ce-doc-18.5 | 0 | 0 |
| Chainguard | gitlab-rails-ce-doc-18.6 | 0 | 0 |
| Chainguard | gitlab-rails-ce-doc-18.7 | 0 | 0 |
| Chainguard | gitlab-rails-ce-doc-fips-18.1 | 0 | 0 |
| Chainguard | gitlab-rails-ce-doc-fips-18.2 | 0 | 0 |
| Chainguard | gitlab-rails-ce-doc-fips-18.3 | 0 | 0 |
| Chainguard | gitlab-rails-ce-doc-fips-18.4 | 0 | 0 |
| Chainguard | gitlab-rails-ce-doc-fips-18.5 | 0 | 0 |
| Chainguard | gitlab-rails-ce-doc-fips-18.6 | 0 | 0 |
| Chainguard | gitlab-rails-ce-doc-fips-18.7 | 0 | 0 |
| Chainguard | gitlab-rails-ce-fips-18.1 | 0 | 0 |
| Chainguard | gitlab-rails-ce-fips-18.2 | 0 | 0 |
| Chainguard | gitlab-rails-ce-fips-18.3 | 0 | 0 |
| Chainguard | gitlab-rails-ce-fips-18.4 | 0 | 0 |
| Chainguard | gitlab-rails-ce-fips-18.5 | 0 | 0 |
| Chainguard | gitlab-rails-ce-fips-18.6 | 0 | 0 |
| Chainguard | gitlab-rails-ce-fips-18.7 | 0 | 0 |
| Chainguard | gitlab-rails-ee-17.0 | 0 | 0 |
| Chainguard | gitlab-rails-ee-17.1 | 0 | 0 |
| Chainguard | gitlab-rails-ee-17.10 | 0 | 0 |
| Chainguard | gitlab-rails-ee-17.11 | 0 | 0 |
| Chainguard | gitlab-rails-ee-17.2 | 0 | 0 |
| Chainguard | gitlab-rails-ee-17.3 | 0 | 0 |
| Chainguard | gitlab-rails-ee-17.4 | 0 | 0 |
| Chainguard | gitlab-rails-ee-17.6 | 0 | 0 |
| Chainguard | gitlab-rails-ee-17.7 | 0 | 0 |
| Chainguard | gitlab-rails-ee-17.8 | 0 | 0 |
| Chainguard | gitlab-rails-ee-17.9 | 0 | 0 |
| Chainguard | gitlab-rails-ee-assets-17.10 | 0 | 0 |
| Chainguard | gitlab-rails-ee-assets-17.11 | 0 | 0 |
| Chainguard | gitlab-rails-ee-assets-17.2 | 0 | 0 |
| Chainguard | gitlab-rails-ee-assets-17.3 | 0 | 0 |
| Chainguard | gitlab-rails-ee-assets-17.4 | 0 | 0 |
| Chainguard | gitlab-rails-ee-assets-17.6 | 0 | 0 |
| Chainguard | gitlab-rails-ee-assets-17.7 | 0 | 0 |
| Chainguard | gitlab-rails-ee-assets-17.8 | 0 | 0 |
| Chainguard | gitlab-rails-ee-assets-17.9 | 0 | 0 |
| Chainguard | gitlab-rails-ee-assets-fips-17.10 | 0 | 0 |
| Chainguard | gitlab-rails-ee-assets-fips-17.11 | 0 | 0 |
| Chainguard | gitlab-rails-ee-assets-fips-17.2 | 0 | 0 |
| Chainguard | gitlab-rails-ee-assets-fips-17.3 | 0 | 0 |
| Chainguard | gitlab-rails-ee-assets-fips-17.4 | 0 | 0 |
| Chainguard | gitlab-rails-ee-assets-fips-17.6 | 0 | 0 |
| Chainguard | gitlab-rails-ee-assets-fips-17.7 | 0 | 0 |
| Chainguard | gitlab-rails-ee-assets-fips-17.8 | 0 | 0 |
| Chainguard | gitlab-rails-ee-assets-fips-17.9 | 0 | 0 |
| Chainguard | gitlab-rails-ee-doc-17.10 | 0 | 0 |
| Chainguard | gitlab-rails-ee-doc-17.11 | 0 | 0 |
| Chainguard | gitlab-rails-ee-doc-17.2 | 0 | 0 |
| Chainguard | gitlab-rails-ee-doc-17.3 | 0 | 0 |
| Chainguard | gitlab-rails-ee-doc-17.4 | 0 | 0 |
| Chainguard | gitlab-rails-ee-doc-17.6 | 0 | 0 |
| Chainguard | gitlab-rails-ee-doc-17.7 | 0 | 0 |
| Chainguard | gitlab-rails-ee-doc-17.8 | 0 | 0 |
| Chainguard | gitlab-rails-ee-doc-17.9 | 0 | 0 |
| Chainguard | gitlab-rails-ee-doc-fips-17.10 | 0 | 0 |
| Chainguard | gitlab-rails-ee-doc-fips-17.11 | 0 | 0 |
| Chainguard | gitlab-rails-ee-doc-fips-17.2 | 0 | 0 |
| Chainguard | gitlab-rails-ee-doc-fips-17.3 | 0 | 0 |
| Chainguard | gitlab-rails-ee-doc-fips-17.4 | 0 | 0 |
| Chainguard | gitlab-rails-ee-doc-fips-17.6 | 0 | 0 |
| Chainguard | gitlab-rails-ee-doc-fips-17.7 | 0 | 0 |
| Chainguard | gitlab-rails-ee-doc-fips-17.8 | 0 | 0 |
| Chainguard | gitlab-rails-ee-doc-fips-17.9 | 0 | 0 |
| Chainguard | gitlab-rails-ee-fips-17.0 | 0 | 0 |
| Chainguard | gitlab-rails-ee-fips-17.1 | 0 | 0 |
| Chainguard | gitlab-rails-ee-fips-17.10 | 0 | 0 |
| Chainguard | gitlab-rails-ee-fips-17.11 | 0 | 0 |
| Chainguard | gitlab-rails-ee-fips-17.2 | 0 | 0 |
| Chainguard | gitlab-rails-ee-fips-17.3 | 0 | 0 |
| Chainguard | gitlab-rails-ee-fips-17.4 | 0 | 0 |
| Chainguard | gitlab-rails-ee-fips-17.6 | 0 | 0 |
| Chainguard | gitlab-rails-ee-fips-17.7 | 0 | 0 |
| Chainguard | gitlab-rails-ee-fips-17.8 | 0 | 0 |
| Chainguard | gitlab-rails-ee-fips-17.9 | 0 | 0 |
| Debian:11 | node-handlebars | 0 | 3:4.5.3-1 |
| Debian:12 | node-handlebars | 0 | 3:4.5.3-1 |
| Debian:13 | node-handlebars | 0 | 3:4.5.3-1 |
| Ubuntu:18.04:LTS | node-handlebars | 0 | No fix |
| Ubuntu:20.04:LTS | node-handlebars | 0 | 3:4.5.3-1 |
| Ubuntu:Pro:18.04:LTS | node-handlebars | 0 | No fix |
| Wolfi | code-server | 0 | 0 |
| Wolfi | code-server-compat | 0 | 0 |
| gem | bootstrap-wysihtml5-rails | 0.3.3.5 | No fix |
Related vulnerabilities
- GHSA-7rx3-28cr-v5wh Handlebars.js has a Prototype Method Access Control Gap via Missing __lookupSetter__… Also affects handlebars
- GHSA-442j-39wm-28r2 Handlebars.js has a Property Access Validation Bypass in container.lookup Also affects handlebars
- CVE-2026-33940 Handlebars provides the power necessary to let users build semantic templates. Also affects handlebars
- CVE-2026-33941 Handlebars provides the power necessary to let users build semantic templates. Also affects handlebars
- CVE-2026-33939 Handlebars provides the power necessary to let users build semantic templates. Also affects handlebars
- CVE-2026-33937 Handlebars provides the power necessary to let users build semantic templates. Also affects handlebars
- CVE-2026-33938 Handlebars provides the power necessary to let users build semantic templates. Also affects handlebars
- CVE-2026-33916 Handlebars provides the power necessary to let users build semantic templates. Also affects handlebars