From 032fbaf5f0b98fce70c8cc380e0d05177a9c9073 Mon Sep 17 00:00:00 2001 From: isaacs Date: Wed, 9 Dec 2020 13:33:13 -0800 Subject: [PATCH] Use Object.create(null) to avoid default object property hazards --- ini.js | 11 ++++++----- test/proto.js | 41 +++++++++++++++++++++++++++-------------- 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/ini.js b/ini.js index 0401258..527f0e3 100644 --- a/ini.js +++ b/ini.js @@ -18,7 +18,7 @@ function encode (obj, opt) { whitespace: false } } else { - opt = opt || {} + opt = opt || Object.create(null) opt.whitespace = opt.whitespace === true } @@ -67,7 +67,7 @@ function dotSplit (str) { } function decode (str) { - var out = {} + var out = Object.create(null) var p = out var section = null // section |key = value @@ -83,13 +83,14 @@ function decode (str) { if (section === '__proto__') { // not allowed // keep parsing the section, but don't attach it. - p = {} + p = Object.create(null) return } - p = out[section] = out[section] || {} + p = out[section] = out[section] || Object.create(null) return } var key = unsafe(match[2]) + if (key === '__proto__') return var value = match[3] ? unsafe(match[4]) : true switch (value) { case 'true': @@ -133,7 +134,7 @@ function decode (str) { var nl = l.replace(/\\\./g, '.') parts.forEach(function (part, _, __) { if (part === '__proto__') return - if (!p[part] || typeof p[part] !== 'object') p[part] = {} + if (!p[part] || typeof p[part] !== 'object') p[part] = Object.create(null) p = p[part] }) if (p === out && nl === l) { diff --git a/test/proto.js b/test/proto.js index ab35533..381fda6 100644 --- a/test/proto.js +++ b/test/proto.js @@ -3,6 +3,7 @@ var t = require('tap') var data = ` __proto__ = quux +constructor.prototype.foo = asdfasdf foo = baz [__proto__] foo = bar @@ -15,27 +16,39 @@ hello = snyk __proto__[] = you did a good job __proto__[] = so you deserve arrays thanks = true +[ctor.constructor.prototype] +foo = asdfasdf ` + var res = ini.parse(data) -t.deepEqual(res, { + +t.deepEqual(res, Object.assign(Object.create(null), { + 'constructor.prototype.foo': 'asdfasdf', foo: 'baz', - other: { + other: Object.assign(Object.create(null), { foo: 'asdf', - }, - kid: { - foo: { + }), + kid: Object.assign(Object.create(null), { + foo: Object.assign(Object.create(null), { foo: 'kid', - }, - }, - arrproto: { + }), + }), + arrproto: Object.assign(Object.create(null), { hello: 'snyk', thanks: true, - }, -}) -t.equal(res.__proto__, Object.prototype) -t.equal(res.kid.__proto__, Object.prototype) -t.equal(res.kid.foo.__proto__, Object.prototype) -t.equal(res.arrproto.__proto__, Object.prototype) + }), + ctor: Object.assign(Object.create(null), { + constructor: Object.assign(Object.create(null), { + prototype: Object.assign(Object.create(null), { + foo: 'asdfasdf', + }), + }), + }), +})) +t.equal(res.__proto__, undefined) +t.equal(res.kid.__proto__, undefined) +t.equal(res.kid.foo.__proto__, undefined) +t.equal(res.arrproto.__proto__, undefined) t.equal(Object.prototype.foo, undefined) t.equal(Object.prototype[0], undefined) t.equal(Object.prototype['0'], undefined)