Dottie vulnerable to prototype pollution bypass via non-first path segments in set() and transform()
Description
Dottie provides nested object access and manipulation in JavaScript. Versions 2.0.4 through 2.0.6 contain an incomplete fix for CVE-2023-26132. The prototype pollution guard introduced in commit 7d3aee1 only validates the first segment of a dot-separated path, allowing an attacker to bypass the protection by placing __proto__ at any position other than the first. Both dottie.set() and dottie.transform() are affected. Version 2.0.7 contains an updated fix to address the residual vulnerability.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Dottie.js 2.0.4-2.0.6 contain an incomplete fix for CVE-2023-26132, allowing prototype pollution bypass via non-first path segments in set() and transform().
Vulnerability
Overview
CVE-2026-27837 affects Dottie.js versions 2.0.4 through 2.0.6, which is a JavaScript library used for nested object access and manipulation. This CVE represents an incomplete fix for the previously disclosed CVE-2023-26132. The original prototype pollution guard, introduced in commit 7d3aee1, only validated the first segment of a dot-separated path against the __proto__ key. This oversight allows an attacker to bypass the protection by placing __proto__ at any position other than the first in the path string [2].
Exploitation and
Attack Surface
An attacker can exploit this vulnerability by supplying a crafted dot-separated path where __proto__ appears as a non-initial segment, for example a.__proto__.polluted. The guard checks only pieces[0] === '__proto__', so when the first segment is something else (like a), the check passes. During the traversal loop, the code sets a property on the object at the path, which triggers the __proto__ setter and replaces the intermediate object's prototype with a new object. The final value is then written onto this new prototype, effectively polluting the prototype chain of that specific object [2]. Both dottie.set() and dottie.transform() are affected [1][2].
Impact
This vulnerability does not pollute the global Object.prototype, but it injects properties into a specific object's prototype chain. The injected properties are invisible to hasOwnProperty() and Object.keys(), making them difficult to detect. The primary risk is authorization bypass, particularly in server-side scenarios where Dottie is used to process user input (e.g., via Sequelize, which depends on Dottie with approximately 1.3 million weekly npm downloads). An attacker can inject properties like isAdmin: true into objects used for access control decisions, potentially gaining unauthorized privileges [2].
Mitigation and
Remediation
The fix was implemented in version 2.0.7, released via commit 7e8fa13 [3]. The updated fix now validates all path segments for dangerous keys (__proto__, constructor, prototype) at any position, not just the first [3]. The repository is marked as unmaintained [4], so users are strongly advised to update to version 2.0.7 or later to mitigate this vulnerability.
- NVD - CVE-2026-27837
- Incomplete fix for CVE-2023-26132: Prototype pollution bypass via non-first path segments in set() and transform()
- fix: check all path segments for dangerous keys (bypass of CVE-2023-2… · mickhansen/dottie.js@7e8fa13
- GitHub - mickhansen/dottie.js: Fast and safe nested object access and manipulation in JavaScript
AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
dottienpm | >= 2.0.4, < 2.0.7 | 2.0.7 |
Affected products
2- Range: >= 2.0.4, < 2.0.7
Patches
17e8fa1345a4bfix: check all path segments for dangerous keys (bypass of CVE-2023-2… (#43)
3 files changed · +144 −2
dottie.js+8 −2 modified@@ -72,8 +72,12 @@ // Set nested value Dottie.set = function(object, path, value, options) { var pieces = Array.isArray(path) ? path : path.split('.'), current = object, piece, length = pieces.length; - if (pieces[0] === '__proto__') return; + // Guard against prototype pollution at ANY position in the path + // Covers __proto__, constructor, and prototype to prevent all known vectors + var DANGEROUS_KEYS = ['__proto__', 'constructor', 'prototype']; + if (pieces.some(function(p) { return DANGEROUS_KEYS.indexOf(p) !== -1; })) return; + if (typeof current !== 'object') { throw new Error('Parent is not an object.'); } @@ -142,7 +146,9 @@ if (key.indexOf(options.delimiter) !== -1) { pieces = key.split(options.delimiter); - if (pieces[0] === '__proto__') break; + // Guard against prototype pollution at ANY position in the path + var DANGEROUS_KEYS = ['__proto__', 'constructor', 'prototype']; + if (pieces.some(function(p) { return DANGEROUS_KEYS.indexOf(p) !== -1; })) break; piecesLength = pieces.length; current = transformed;
test/set.proto-bypass.test.js+67 −0 added@@ -0,0 +1,67 @@ +// test/set.proto-bypass.test.js +// Tests for prototype pollution bypass fix (CVE-2023-26132 bypass) + +var assert = require('assert'); +var dottie = require('../dottie'); + +describe('dottie.set - prototype pollution bypass prevention', function () { + + // === __proto__ at non-first positions === + + it('should block __proto__ at second position', function () { + var obj = {}; + dottie.set(obj, 'a.__proto__.polluted', true); + + // The property should NOT be reachable via prototype chain + assert.strictEqual(obj.a === undefined || obj.a.polluted === undefined, true, + '__proto__ at position 1 should be blocked'); + + // Global Object.prototype must remain clean + assert.strictEqual(({}).polluted, undefined, + 'Object.prototype must not be polluted'); + }); + + it('should block __proto__ at third position', function () { + var obj = {}; + dottie.set(obj, 'a.b.__proto__.polluted', true); + assert.strictEqual(({}).polluted, undefined, + 'Object.prototype must not be polluted'); + }); + + it('should still block __proto__ at first position (original CVE-2023-26132 fix)', function () { + var obj = {}; + dottie.set(obj, '__proto__.polluted', true); + assert.strictEqual(({}).polluted, undefined, + 'Object.prototype must not be polluted'); + }); + + // === constructor and prototype keys === + + it('should block constructor at any position', function () { + var obj = {}; + dottie.set(obj, 'a.constructor.prototype.polluted', true); + assert.strictEqual(({}).polluted, undefined, + 'constructor-based pollution must be blocked'); + }); + + it('should block prototype at any position', function () { + var obj = {}; + dottie.set(obj, 'a.prototype.polluted', true); + assert.strictEqual(({}).polluted, undefined, + 'prototype-based pollution must be blocked'); + }); + + // === Legitimate paths should still work === + + it('should allow normal nested paths', function () { + var obj = {}; + dottie.set(obj, 'a.b.c', 'hello'); + assert.strictEqual(obj.a.b.c, 'hello'); + }); + + it('should allow paths with similar-looking but safe key names', function () { + var obj = {}; + dottie.set(obj, 'user.proto.value', 42); + assert.strictEqual(obj.user.proto.value, 42); + }); +});
test/transform.proto-bypass.test.js+69 −0 added@@ -0,0 +1,69 @@ +// test/transform.proto-bypass.test.js +// Tests for prototype pollution bypass fix in transform() (CVE-2023-26132 bypass) + +var assert = require('assert'); +var dottie = require('../dottie'); + +describe('dottie.transform - prototype pollution bypass prevention', function () { + + // === __proto__ at non-first positions === + + it('should block __proto__ at second position in keys', function () { + var flat = { 'user.__proto__.isAdmin': true, 'user.name': 'guest' }; + var result = dottie.transform(flat); + + // The isAdmin property should NOT be reachable via prototype chain + assert.strictEqual( + result.user === undefined || result.user.isAdmin === undefined, true, + '__proto__ bypass in transform keys should be blocked' + ); + + // Global Object.prototype must remain clean + assert.strictEqual(({}).isAdmin, undefined, + 'Object.prototype must not be polluted'); + }); + + it('should block __proto__ at third position in keys', function () { + var flat = { 'a.b.__proto__.polluted': true }; + var result = dottie.transform(flat); + assert.strictEqual(({}).polluted, undefined, + 'Object.prototype must not be polluted'); + }); + + it('should still block __proto__ at first position (original fix)', function () { + var flat = { '__proto__.polluted': true }; + var result = dottie.transform(flat); + assert.strictEqual(({}).polluted, undefined, + 'Object.prototype must not be polluted'); + }); + + // === constructor and prototype keys === + + it('should block constructor-based pollution in transform keys', function () { + var flat = { 'a.constructor.prototype.polluted': true }; + var result = dottie.transform(flat); + assert.strictEqual(({}).polluted, undefined, + 'constructor-based pollution must be blocked'); + }); + + it('should block prototype key in transform keys', function () { + var flat = { 'a.prototype.polluted': true }; + var result = dottie.transform(flat); + assert.strictEqual(({}).polluted, undefined, + 'prototype-based pollution must be blocked'); + }); + + // === Legitimate transforms should still work === + + it('should transform normal dotted keys correctly', function () { + var flat = { + 'user.name': 'Alice', + 'user.email': 'alice@example.com', + 'user.settings.theme': 'dark' + }; + var result = dottie.transform(flat); + assert.strictEqual(result.user.name, 'Alice'); + assert.strictEqual(result.user.email, 'alice@example.com'); + assert.strictEqual(result.user.settings.theme, 'dark'); + }); +});
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-4gxf-g5gf-22h4ghsax_refsource_MISCADVISORY
- github.com/advisories/GHSA-r5mx-6wc6-7h9wghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-27837ghsaADVISORY
- github.com/mickhansen/dottie.js/commit/7e8fa1345a4b46325f0eab8d7aeb1c4deaefdb14ghsax_refsource_MISCWEB
- github.com/mickhansen/dottie.js/security/advisories/GHSA-r5mx-6wc6-7h9wghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.