From 0877cc871db9865f58dd9389ce99e61be05380a5 Mon Sep 17 00:00:00 2001 From: Steve King Date: Wed, 30 Dec 2020 08:54:03 +0200 Subject: [PATCH] Test case covering the use of `__proto__` as a section name Closes #40 --- src/properties-reader.js | 9 ++++++++- test/fix-prototype-pollution.spec.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 test/fix-prototype-pollution.spec.js diff --git a/src/properties-reader.js b/src/properties-reader.js index 1db639d..08ec72d 100644 --- a/src/properties-reader.js +++ b/src/properties-reader.js @@ -2,6 +2,8 @@ const {readFileSync, statSync} = require('fs'); const propertyAppender = require('./property-appender').propertyAppender; const propertyWriter = require('./property-writer').propertyWriter; +const has = Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty); + const SECTION = Symbol('SECTION'); function PropertiesReader (sourceFile, encoding, options = {}) { @@ -213,7 +215,12 @@ PropertiesReader.prototype.set = function (key, value) { if (expanded.length >= 1 && typeof source[step] === 'string') { source[step] = {'': source[step]}; } - source = (source[step] = source[step] || {}); + + if (!has(source, step)) { + Object.defineProperty(source, step, { value: Object.create(null) }); + } + + source = source[step] } if (typeof parsedValue === 'string' && typeof source[expanded[0]] === 'object') { diff --git a/test/fix-prototype-pollution.spec.js b/test/fix-prototype-pollution.spec.js new file mode 100644 index 0000000..19f0e21 --- /dev/null +++ b/test/fix-prototype-pollution.spec.js @@ -0,0 +1,28 @@ +const {createTestContext} = require('./__fixtues__/create-test-context'); + +const propertiesReader = require('../'); + +describe('prototype-pollution', () => { + let context; + + beforeEach(async () => { + context = await createTestContext(); + }); + + it('does not pollute global Object.prototype', async () => { + const file = ` + [__proto__] + polluted = polluted + parsed = true + `; + const props = propertiesReader(await context.file('props.ini', file)); + + expect(({}).polluted).toBeUndefined(); + expect(props.path().__proto__.polluted).toBe('polluted'); + expect(props.getRaw('__proto__.polluted')).toBe('polluted'); + expect(props.get('__proto__.polluted')).toBe('polluted'); + expect(props.getRaw('__proto__.parsed')).toBe('true'); + expect(props.get('__proto__.parsed')).toBe(true); + }); + +});