0

First of all, I want to say that I know that extending global methods is not a good practice, but there are situations where a developer needs to avoid duplicating objects due to size or other reasons, and global functions can help a lot in such situations.(at least that's what I believe)

I raised this topic because I think it's strange that this "bug" (example below) still exists in JavaScript, because if I'm not mistaken about 5 years ago I needed to traverse a window object with a loop and I ended up finding it, but since so much time has passed and it still exists I think it might be normal for Object.prototype

Can anyone tell me if it's a forgotten bug or is it a normal occurrence? can't this be exploited as code injection along with this?

Object.prototype.foo = function(){
  for(index in this) console.log(index)
}

var A = [1,2,3];

//returns a non-iterable index at the end
A.foo();   

function bar(attr){
  var B = {a:1, b:2,c:3}
  for(index in B) console.log(index);
  for(index in attr) console.log(index);
}

//all the 'in' iterations will start printing the index value at the end
bar([1,2,3,4,5]);
for(index in {x:1, y:2,z:3}) console.log(index);
  • See [How to define method in javascript on Array.prototype and Object.prototype so that it doesn't appear in for in loop](https://stackoverflow.com/q/13296340/1048572). It's absolutely normal behaviour, not a bug, you just should not do it. – Bergi Jan 04 '22 at 04:19

2 Answers2

1

This is completely normal and expected.

for..in iterates over all enumerable own properties on the object in question. Then it does the same for that object's internal prototype, and so on - until it reaches the beginning of the prototype chain (which is often Object.prototype).

If you put an enumerable property onto Object.prototype, then any object (that inherits from Object.prototype) you iterate over with for..in will eventually iterate over that property you added.

can't this be exploited as code injection along with this?

I suppose - malicious code can modify Object.prototype and do a whole lot of other nasty things, so take care not to run anything that isn't trustworthy.

Accidental prototype pollution (even occasionally from user input) isn't an uncommon problem that libraries sometimes run into. A good rule of thumb is to use static key names everywhere - if you need something dynamic, use a Map instead of an object.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • I had never noticed it. I always thought that native objects already did this automatically (but if they don't they should) –  Jan 04 '22 at 05:18
0

The behavior you're observing is normal. The properties defined on Object.prototype will be prototype linked to by its instances. The for..in will iterate over all enumerable properties of an object, whether owned or inherited.

You can access foo at A.__proto__.__proto__.foo.
A is an instance of Array[], which is an instance of the global Object{}.


From MDN Web Docs:

The enumerable property attribute defines whether the property is picked by Object.assign() or spread operator. For non-Symbol properties it also defines whether it shows up in a for...in loop and Object.keys() or not.

You can define the property as an innumerable attribute by setting the enumerable flag to false.

Object.defineProperty(Object.prototype, "foo", {
  value: function(){
    for(index in this) console.log(index);
  },
  configurable: true,
  enumerable: false
});

You could freeze the the Object.prototype by:

Object.freeze(Object.prototype);
Object.freeze(Object);

to prevent attackers from polluting it.

Vektor
  • 697
  • 5
  • 14