Skip to content

Commit 60f2e17

Browse files
authored
Merge pull request #14 from reedsy/proto-guard
Guard against prototype pollution in json0
2 parents af471ec + 46dd037 commit 60f2e17

File tree

2 files changed

+16
-1
lines changed

2 files changed

+16
-1
lines changed

lib/json0.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ var isObject = function(obj) {
3434
return (!!obj) && (obj.constructor === Object);
3535
};
3636

37+
var hasOwn = Object.hasOwn || Object.prototype.hasOwnProperty.call;
38+
3739
/**
3840
* Clones the passed object using JSON serialization (which is slow).
3941
*
@@ -57,7 +59,7 @@ var json = {
5759
// You can register another OT type as a subtype in a JSON document using
5860
// the following function. This allows another type to handle certain
5961
// operations instead of the builtin JSON type.
60-
var subtypes = {};
62+
var subtypes = Object.create(null);
6163
json.registerSubtype = function(subtype) {
6264
subtypes[subtype.name] = subtype;
6365
};
@@ -177,6 +179,9 @@ json.apply = function(snapshot, op) {
177179
for (var j = 0; j < c.p.length; j++) {
178180
var p = c.p[j];
179181

182+
if (p in elem && !hasOwn(elem, p))
183+
throw new Error('Path invalid');
184+
180185
parent = elem;
181186
parentKey = key;
182187
elem = elem[key];

test/json0.coffee

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,16 @@ genTests = (type) ->
452452
assert.throws -> type.apply {x:'a'}, [{p:['x'], oi: 'c', od: 'b'}]
453453
assert.throws -> type.apply {x:'a'}, [{p:['x'], oi: 'b'}]
454454

455+
it 'disallows reassignment of special JS property names', ->
456+
assert.throws -> type.apply {x:'a'}, [{p:['__proto__'], oi:'oops'}]
457+
assert.throws -> type.apply {x:{y:'a'}}, [{p:['x', '__proto__'], oi:'oops'}]
458+
assert.throws -> type.apply {x:'a'}, [{p:['constructor'], oi:'oops'}]
459+
assert.throws -> type.apply {x:{y:'a'}}, [{p:['x', 'constructor'], oi:'oops'}]
460+
461+
it 'disallows modification of prototype property objects', ->
462+
obj = {x:'a'}
463+
assert.throws -> type.apply obj, [{p:['toString', 'name'], oi:'oops'}]
464+
455465
it 'throws when the insertion key is a number', ->
456466
assert.throws -> type.apply {'1':'a'}, [{p:[2], oi: 'a'}]
457467

0 commit comments

Comments
 (0)