Skip to content

Commit 26f64b6

Browse files
authored
Merge pull request #25 from fastify/improve-contractor-detection
Throw only if the constructor key has a child named prototype
2 parents edce4af + 4a39a3c commit 26f64b6

File tree

3 files changed

+19
-4
lines changed

3 files changed

+19
-4
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ npm install secure-json-parse
3838
## Usage
3939

4040
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`.<br/>
41-
You can choose which action to perform in case `__proto__` is present, and in case `constructor` is present.
41+
You can choose which action to perform in case `__proto__` is present, and in case `constructor.prototype` is present.
4242

4343
```js
4444
const sjson = require('secure-json-parse')
@@ -63,7 +63,7 @@ Parses a given JSON-formatted text into an object where:
6363
- `'remove'` - deletes any `__proto__` keys from the result object.
6464
- `'ignore'` - skips all validation (same as calling `JSON.parse()` directly).
6565
- `constructorAction` - optional string with one of:
66-
- `'error'` - throw a `SyntaxError` when a `constructor` key is found. This is the default value.
66+
- `'error'` - throw a `SyntaxError` when a `constructor.prototype` key is found. This is the default value.
6767
- `'remove'` - deletes any `constructor` keys from the result object.
6868
- `'ignore'` - skips all validation (same as calling `JSON.parse()` directly).
6969

@@ -76,7 +76,7 @@ Scans a given object for prototype properties where:
7676
- `'error'` - throw a `SyntaxError` when a `__proto__` key is found. This is the default value.
7777
- `'remove'` - deletes any `__proto__` keys from the input `obj`.
7878
- `constructorAction` - optional string with one of:
79-
- `'error'` - throw a `SyntaxError` when a `constructor` key is found. This is the default value.
79+
- `'error'` - throw a `SyntaxError` when a `constructor.prototype` key is found. This is the default value.
8080
- `'remove'` - deletes any `constructor` keys from the input `obj`.
8181

8282
## Benchmarks

index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ function scan (obj, { protoAction = 'error', constructorAction = 'error' } = {})
7676
delete node.__proto__ // eslint-disable-line no-proto
7777
}
7878

79-
if (constructorAction !== 'ignore' && Object.prototype.hasOwnProperty.call(node, 'constructor')) { // Avoid calling node.hasOwnProperty directly
79+
if (constructorAction !== 'ignore' &&
80+
Object.prototype.hasOwnProperty.call(node, 'constructor') &&
81+
Object.prototype.hasOwnProperty.call(node.constructor, 'prototype')) { // Avoid calling node.hasOwnProperty directly
8082
if (constructorAction === 'error') {
8183
throw new SyntaxError('Object contains forbidden prototype property')
8284
}

test.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,14 @@ test('parse', t => {
185185
t.end()
186186
})
187187

188+
t.test('sanitizes object string (no prototype key)', t => {
189+
t.deepEqual(
190+
j.parse('{"a": 5, "b": 6,"constructor":{"bar":"baz"} }', { constructorAction: 'remove' }),
191+
{ a: 5, b: 6, constructor: { bar: 'baz' } }
192+
)
193+
t.end()
194+
})
195+
188196
t.test('sanitizes nested object string', t => {
189197
t.deepEqual(
190198
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 => {
217225
t.end()
218226
})
219227

228+
t.test('Should not throw if the constructor key hasn\'t a child named prototype', t => {
229+
t.doesNotThrow(() => j.parse('{ "a": 5, "b": 6, "constructor":{"bar":"baz"} }', null, null), SyntaxError)
230+
t.end()
231+
})
232+
220233
t.test('errors on proto property (null, null)', t => {
221234
t.throws(() => j.parse('{ "a": 5, "b": 6, "constructor":{"prototype":{"bar":"baz"}} }', null, null), SyntaxError)
222235
t.end()

0 commit comments

Comments
 (0)