From 027457f7222eef6ae37592d7cbf2aabb85aaaea5 Mon Sep 17 00:00:00 2001 From: dellalibera <43420907+dellalibera@users.noreply.github.com> Date: Mon, 27 Sep 2021 18:17:39 +0200 Subject: [PATCH 1/3] fix-prototype-pollution --- jsonpointer.js | 10 +++++++--- test.js | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/jsonpointer.js b/jsonpointer.js index 3635882..31cef2a 100644 --- a/jsonpointer.js +++ b/jsonpointer.js @@ -17,10 +17,9 @@ function setter (obj, pointer, value) { var part var hasNextPart - if (pointer[1] === 'constructor' && pointer[2] === 'prototype') return obj - if (pointer[1] === '__proto__') return obj - for (var p = 1, len = pointer.length; p < len;) { + if (pointer[p] === 'constructor' || pointer[p] === 'prototype' || pointer[p] === '__proto__') return obj + part = untilde(pointer[p++]) hasNextPart = len > p @@ -53,6 +52,11 @@ function compilePointer (pointer) { if (pointer[0] === '') return pointer throw new Error('Invalid JSON pointer.') } else if (Array.isArray(pointer)) { + pointer.forEach(function (part, i) { + if (typeof part !== 'string' && typeof part !== 'number') { + pointer[i] = '' + part + } + }) return pointer } diff --git a/test.js b/test.js index 09861b3..00adb40 100644 --- a/test.js +++ b/test.js @@ -136,4 +136,49 @@ var c = {} jsonpointer.set({}, '/__proto__/boo', 'polluted') assert(!c.boo, 'should not boo') +var d = {} +jsonpointer.set({}, '/foo/__proto__/boo', 'polluted') +assert(!d.boo, 'should not boo') + +jsonpointer.set({}, '/foo/__proto__/__proto__/boo', 'polluted') +assert(!d.boo, 'should not boo') + +var e = {} +jsonpointer.set({}, '/constructor/prototype/boo', 'polluted') +assert(!e.boo, 'should not boo') + +jsonpointer.set({}, '/foo/constructor/prototype/boo', 'polluted') +assert(!e.boo, 'should not boo') + +jsonpointer.set({}, '/foo/constructor/constructor/prototype/boo', 'polluted') +assert(!e.boo, 'should not boo') + +var f = {} +jsonpointer.set({}, [['__proto__'], 'boo'], 'polluted') +assert(!f.boo, 'should not f.boo') + +jsonpointer.set({}, [[['__proto__']], 'boo'], 'polluted') +assert(!f.boo, 'should not f.boo') + +jsonpointer.set({}, [['__proto__'], ['__proto__'], 'boo'], 'polluted') +assert(!f.boo, 'should not f.boo') + +jsonpointer.set({}, [[['__proto__']], [['__proto__']], 'boo'], 'polluted') +assert(!f.boo, 'should not f.boo') + +jsonpointer.set({}, [['__proto__'], ['__proto__'], ['__proto__'], 'boo'], 'polluted') +assert(!f.boo, 'should not f.boo') + +jsonpointer.set({}, [['foo'], ['__proto__'], 'boo'], 'polluted') +assert(!f.boo, 'should not boo') + +jsonpointer.set({}, [['foo'], ['__proto__'], ['__proto__'], 'boo'], 'polluted') +assert(!f.boo, 'should not boo') + +jsonpointer.set({}, [['constructor'], ['prototype'], 'boo'], 'polluted') +assert(!f.boo, 'should not boo') + +jsonpointer.set({}, [['constructor'], ['constructor'], ['prototype'], 'boo'], 'polluted') +assert(!f.boo, 'should not boo') + console.log('All tests pass.') From 747ee17c0c309ea2fe79e5e351aa8413b7005c69 Mon Sep 17 00:00:00 2001 From: dellalibera <43420907+dellalibera@users.noreply.github.com> Date: Sun, 31 Oct 2021 16:08:48 +0100 Subject: [PATCH 2/3] Accepts only strings or numbers --- jsonpointer.js | 6 +++--- test.js | 39 +++++++++------------------------------ 2 files changed, 12 insertions(+), 33 deletions(-) diff --git a/jsonpointer.js b/jsonpointer.js index 31cef2a..d17f60a 100644 --- a/jsonpointer.js +++ b/jsonpointer.js @@ -52,11 +52,11 @@ function compilePointer (pointer) { if (pointer[0] === '') return pointer throw new Error('Invalid JSON pointer.') } else if (Array.isArray(pointer)) { - pointer.forEach(function (part, i) { + for (const part of pointer) { if (typeof part !== 'string' && typeof part !== 'number') { - pointer[i] = '' + part + throw new Error('Invalid JSON pointer.') } - }) + } return pointer } diff --git a/test.js b/test.js index 00adb40..33c639a 100644 --- a/test.js +++ b/test.js @@ -144,41 +144,20 @@ jsonpointer.set({}, '/foo/__proto__/__proto__/boo', 'polluted') assert(!d.boo, 'should not boo') var e = {} -jsonpointer.set({}, '/constructor/prototype/boo', 'polluted') -assert(!e.boo, 'should not boo') - jsonpointer.set({}, '/foo/constructor/prototype/boo', 'polluted') assert(!e.boo, 'should not boo') jsonpointer.set({}, '/foo/constructor/constructor/prototype/boo', 'polluted') assert(!e.boo, 'should not boo') -var f = {} -jsonpointer.set({}, [['__proto__'], 'boo'], 'polluted') -assert(!f.boo, 'should not f.boo') - -jsonpointer.set({}, [[['__proto__']], 'boo'], 'polluted') -assert(!f.boo, 'should not f.boo') - -jsonpointer.set({}, [['__proto__'], ['__proto__'], 'boo'], 'polluted') -assert(!f.boo, 'should not f.boo') - -jsonpointer.set({}, [[['__proto__']], [['__proto__']], 'boo'], 'polluted') -assert(!f.boo, 'should not f.boo') - -jsonpointer.set({}, [['__proto__'], ['__proto__'], ['__proto__'], 'boo'], 'polluted') -assert(!f.boo, 'should not f.boo') - -jsonpointer.set({}, [['foo'], ['__proto__'], 'boo'], 'polluted') -assert(!f.boo, 'should not boo') - -jsonpointer.set({}, [['foo'], ['__proto__'], ['__proto__'], 'boo'], 'polluted') -assert(!f.boo, 'should not boo') - -jsonpointer.set({}, [['constructor'], ['prototype'], 'boo'], 'polluted') -assert(!f.boo, 'should not boo') - -jsonpointer.set({}, [['constructor'], ['constructor'], ['prototype'], 'boo'], 'polluted') -assert(!f.boo, 'should not boo') +assert.throws(function () { jsonpointer.set({}, [['__proto__'], 'boo'], 'polluted')}, validateError) +assert.throws(function () { jsonpointer.set({}, [[['__proto__']], 'boo'], 'polluted')}, validateError) +assert.throws(function () { jsonpointer.set({}, [['__proto__'], ['__proto__'], 'boo'], 'polluted')}, validateError) +assert.throws(function () { jsonpointer.set({}, [[['__proto__']], [['__proto__']], 'boo'], 'polluted')}, validateError) +assert.throws(function () { jsonpointer.set({}, [['__proto__'], ['__proto__'], ['__proto__'], 'boo'], 'polluted')}, validateError) +assert.throws(function () { jsonpointer.set({}, [['foo'], ['__proto__'], 'boo'], 'polluted')}, validateError) +assert.throws(function () { jsonpointer.set({}, [['foo'], ['__proto__'], ['__proto__'], 'boo'], 'polluted')}, validateError) +assert.throws(function () { jsonpointer.set({}, [['constructor'], ['prototype'], 'boo'], 'polluted')}, validateError) +assert.throws(function () { jsonpointer.set({}, [['constructor'], ['constructor'], ['prototype'], 'boo'], 'polluted')}, validateError) console.log('All tests pass.') From 00c9afe0b7dbe519acffeef831f637a94b4962b8 Mon Sep 17 00:00:00 2001 From: Jan Lehnardt Date: Sun, 31 Oct 2021 18:09:57 +0100 Subject: [PATCH 3/3] specify type requirements in error message --- jsonpointer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsonpointer.js b/jsonpointer.js index d17f60a..3f6f353 100644 --- a/jsonpointer.js +++ b/jsonpointer.js @@ -54,7 +54,7 @@ function compilePointer (pointer) { } else if (Array.isArray(pointer)) { for (const part of pointer) { if (typeof part !== 'string' && typeof part !== 'number') { - throw new Error('Invalid JSON pointer.') + throw new Error('Invalid JSON pointer. Must be of type string or number.') } } return pointer