diff --git a/index.js b/index.js index 30e26f5..9bc6a4c 100644 --- a/index.js +++ b/index.js @@ -33,6 +33,11 @@ const mapObject = (object, mapper, options, isSeen = new WeakMap()) => { for (const [key, value] of Object.entries(object)) { let [newKey, newValue, {shouldRecurse = true} = {}] = mapper(key, value, object); + // Drop `__proto__` keys. + if (newKey === '__proto__') { + continue; + } + if (options.deep && shouldRecurse && isObjectCustom(newValue)) { newValue = Array.isArray(newValue) ? mapArray(newValue) : diff --git a/test.js b/test.js index ee57c23..6ff4bab 100644 --- a/test.js +++ b/test.js @@ -153,14 +153,13 @@ test('validates input', t => { }, TypeError); }); -test.failing('identity function preserves __proto__ keys', t => { +test('__proto__ keys are safely dropped', t => { const input = {['__proto__']: {one: 1}}; - t.deepEqual(mapObject(input, (key, value) => [key, value]), input); -}); + const output = mapObject(input, (key, value) => [key, value]); + t.deepEqual(output, {}); -test.failing('mapper can produce __proto__ keys', t => { - t.deepEqual( - mapObject({proto: {one: 1}}, (key, value) => [`__${key}__`, value]), - {['__proto__']: {one: 1}} - ); + // AVA's equality checking isn't quite strict enough to catch the difference + // between plain objects as prototypes and Object.prototype, so we also check + // the prototype by identity + t.is(Object.getPrototypeOf(output), Object.prototype); });