From f486879bd0ec52a15b730965adf566ad123e7e24 Mon Sep 17 00:00:00 2001 From: delvedor Date: Mon, 8 Mar 2021 19:27:49 +0100 Subject: [PATCH 1/3] Throw only if the constructor key has a child named prototype --- index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index d1513be..7508655 100755 --- a/index.js +++ b/index.js @@ -76,7 +76,9 @@ function scan (obj, { protoAction = 'error', constructorAction = 'error' } = {}) delete node.__proto__ // eslint-disable-line no-proto } - if (constructorAction !== 'ignore' && Object.prototype.hasOwnProperty.call(node, 'constructor')) { // Avoid calling node.hasOwnProperty directly + if (constructorAction !== 'ignore' && + Object.prototype.hasOwnProperty.call(node, 'constructor') && + Object.prototype.hasOwnProperty.call(node.constructor, 'prototype')) { // Avoid calling node.hasOwnProperty directly if (constructorAction === 'error') { throw new SyntaxError('Object contains forbidden prototype property') } From 015688749f0c42913513c33f8222c8ecb80e013e Mon Sep 17 00:00:00 2001 From: delvedor Date: Mon, 8 Mar 2021 19:27:55 +0100 Subject: [PATCH 2/3] Updated test --- test.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test.js b/test.js index 1d04fee..51a9e47 100644 --- a/test.js +++ b/test.js @@ -185,6 +185,14 @@ test('parse', t => { t.end() }) + t.test('sanitizes object string (no prototype key)', t => { + t.deepEqual( + j.parse('{"a": 5, "b": 6,"constructor":{"bar":"baz"} }', { constructorAction: 'remove' }), + { a: 5, b: 6, constructor: { bar: 'baz' } } + ) + t.end() + }) + t.test('sanitizes nested object string', t => { t.deepEqual( j.parse('{ "a": 5, "b": 6, "constructor":{"prototype":{"bar":"baz"}}, "c": { "d": 0, "e": "text", "constructor":{"prototype":{"bar":"baz"}}, "f": { "g": 2 } } }', { constructorAction: 'remove' }), @@ -217,6 +225,11 @@ test('parse', t => { t.end() }) + t.test('Should not throw if the constructor key hasn\'t a child named prototype', t => { + t.doesNotThrow(() => j.parse('{ "a": 5, "b": 6, "constructor":{"bar":"baz"} }', null, null), SyntaxError) + t.end() + }) + t.test('errors on proto property (null, null)', t => { t.throws(() => j.parse('{ "a": 5, "b": 6, "constructor":{"prototype":{"bar":"baz"}} }', null, null), SyntaxError) t.end() From 4a39a3ce036acab5e7e4aa62d851e0de9457968c Mon Sep 17 00:00:00 2001 From: delvedor Date: Mon, 8 Mar 2021 19:27:59 +0100 Subject: [PATCH 3/3] Updated README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c6d18cf..96b250d 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ npm install secure-json-parse ## Usage Pass the option object as a second (or third) parameter for configuring the action to take in case of a bad JSON, if nothing is configured, the default is to throw a `SyntaxError`.
-You can choose which action to perform in case `__proto__` is present, and in case `constructor` is present. +You can choose which action to perform in case `__proto__` is present, and in case `constructor.prototype` is present. ```js const sjson = require('secure-json-parse') @@ -63,7 +63,7 @@ Parses a given JSON-formatted text into an object where: - `'remove'` - deletes any `__proto__` keys from the result object. - `'ignore'` - skips all validation (same as calling `JSON.parse()` directly). - `constructorAction` - optional string with one of: - - `'error'` - throw a `SyntaxError` when a `constructor` key is found. This is the default value. + - `'error'` - throw a `SyntaxError` when a `constructor.prototype` key is found. This is the default value. - `'remove'` - deletes any `constructor` keys from the result object. - `'ignore'` - skips all validation (same as calling `JSON.parse()` directly). @@ -76,7 +76,7 @@ Scans a given object for prototype properties where: - `'error'` - throw a `SyntaxError` when a `__proto__` key is found. This is the default value. - `'remove'` - deletes any `__proto__` keys from the input `obj`. - `constructorAction` - optional string with one of: - - `'error'` - throw a `SyntaxError` when a `constructor` key is found. This is the default value. + - `'error'` - throw a `SyntaxError` when a `constructor.prototype` key is found. This is the default value. - `'remove'` - deletes any `constructor` keys from the input `obj`. ## Benchmarks