From acff7431139a7ba56645cbe8b223d8972e65f966 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Mon, 11 Jul 2022 10:48:41 +0200 Subject: [PATCH] lib: make `validateObject` less affected by prototype tampering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/42929 Reviewed-By: Tobias Nießen --- lib/internal/validators.js | 14 ++++++++++---- test/parallel/test-validators.js | 13 +++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/lib/internal/validators.js b/lib/internal/validators.js index 11cccf2040cd36..006b952de0d7a2 100644 --- a/lib/internal/validators.js +++ b/lib/internal/validators.js @@ -10,6 +10,7 @@ const { NumberMAX_SAFE_INTEGER, NumberMIN_SAFE_INTEGER, NumberParseInt, + ObjectPrototypeHasOwnProperty, RegExpPrototypeExec, String, StringPrototypeToUpperCase, @@ -150,6 +151,12 @@ function validateBoolean(value, name) { throw new ERR_INVALID_ARG_TYPE(name, 'boolean', value); } +function getOwnPropertyValueOrDefault(options, key, defaultValue) { + return options == null || !ObjectPrototypeHasOwnProperty(options, key) ? + defaultValue : + options[key]; +} + /** * @param {unknown} value * @param {string} name @@ -161,10 +168,9 @@ function validateBoolean(value, name) { */ const validateObject = hideStackFrames( (value, name, options) => { - const useDefaultOptions = options == null; - const allowArray = useDefaultOptions ? false : options.allowArray; - const allowFunction = useDefaultOptions ? false : options.allowFunction; - const nullable = useDefaultOptions ? false : options.nullable; + const allowArray = getOwnPropertyValueOrDefault(options, 'allowArray', false); + const allowFunction = getOwnPropertyValueOrDefault(options, 'allowFunction', false); + const nullable = getOwnPropertyValueOrDefault(options, 'nullable', false); if ((!nullable && value === null) || (!allowArray && ArrayIsArray(value)) || (typeof value !== 'object' && ( diff --git a/test/parallel/test-validators.js b/test/parallel/test-validators.js index 0bba9d13b20bf0..63cf42e306605c 100644 --- a/test/parallel/test-validators.js +++ b/test/parallel/test-validators.js @@ -105,6 +105,10 @@ const invalidArgValueError = { { // validateObject tests. + Object.prototype.nullable = true; + Object.prototype.allowArray = true; + Object.prototype.allowFunction = true; + validateObject({}, 'foo'); validateObject({ a: 42, b: 'foo' }, 'foo'); @@ -119,6 +123,15 @@ const invalidArgValueError = { validateObject(null, 'foo', { nullable: true }); validateObject([], 'foo', { allowArray: true }); validateObject(() => {}, 'foo', { allowFunction: true }); + + // validateObject should not be affected by Object.prototype tampering. + assert.throws(() => validateObject(null, 'foo', { allowArray: true }), invalidArgTypeError); + assert.throws(() => validateObject([], 'foo', { nullable: true }), invalidArgTypeError); + assert.throws(() => validateObject(() => {}, 'foo', { nullable: true }), invalidArgTypeError); + + delete Object.prototype.nullable; + delete Object.prototype.allowArray; + delete Object.prototype.allowFunction; } {