1

I want to use a JavaScript object ({}) as a dictionary to store untrusted data. (I know there's Map, but let's say I don't want to use Map.)

If I write

let obj = {};
obj[key] = value;

where key and value are supplied by an unstrusted source, what keys can cause surprising behavior?

I know that assigning obj.__proto__ can change the object's prototype and therefore change the behavior of the object. (This is sometimes called prototype poisoning.) So I should probably exclude '__proto__':

let obj = {};
if (key !== '__proto__') {
  obj[key] = value;
}

Are there other such unsafe keys that can change an object's behavior in some way, or is '__proto__' the only one?

Bonus points if you cite the ECMAScript spec or a reference document.

Jo Liss
  • 30,333
  • 19
  • 121
  • 170
  • 1
    If you don't want to use a `Map` (for some reason), at least use `Object.create(null)` instead of `{}`. – Bergi May 21 '20 at 18:39

2 Answers2

3

All of the properties on Object.prototype can cause problematic name collisions:

console.log(
  Object.getOwnPropertyNames(Object.prototype)
);

That's it.

Another option to avoid having to worry about name collisions is to make an object which doesn't inherit from Object.prototype, eg:

const obj = Object.create(null);

// Now, this is perfectly fine (though weird):
obj.__proto__ = 'foo';
console.log(obj.__proto__);
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
-1

If you're simply looking for excluding extant values from the prototype you can use a combination of two checks:

1) Is the property they are trying to set already present in the object:

const exists = '__proto__' in obj; // Or whichever property name they are setting

2) And if so, is it direct property, or does it come from upstream (e.g. you may allow them to set/overwrite existing properties they have previous set directly on the object).

const onSelf = obj.hasOwnProperty('__proto__'); // Or whichever property name they are setting

Then maybe your protection would look like:

if (!(key in obj) || obj.hasOwnProperty(key)) {
  obj[key] = value;
}

See:

Chase
  • 3,028
  • 14
  • 15
  • 1
    what if i create an own property named "hasOwnProperty" ? facepalm. `{hasOwnProperty:Boolean}` – dandavis May 21 '20 at 18:53
  • [Why use `Object.prototype.hasOwnProperty.call(myObj, prop)` instead of `myObj.hasOwnProperty(prop)`?](https://stackoverflow.com/q/12017693/1048572) – Bergi May 21 '20 at 19:06