Reputation: 368
I took a look at one of the rules from eslint-plugin-security and found that user input could in theory lead to a Remote Code Execution bug.
const a = class {};
console.log(a['constructor']);
a['constructor']('console.log(1)')();
function b() {}
console.log(b['constructor']);
b['constructor']('console.log(2)')();
const c = {}
console.log(c['constructor'])
console.log(c['constructor']('console.log(3)')());
From the snippet it's easy to see that constructors of classes and functions seem to parse strings and evaluate them as valid code. Objects for some reason don't exhibit this behaviour.
Why is this even allowed to happen? What feature of JavaScript needs this behaviour from function/class constructors? I'm assuming it's integral to the way JavaScript works otherwise I don't see why it hasn't been removed from the language.
Upvotes: 3
Views: 421
Reputation: 371019
The problem is that the .constructor
of a class is Function
, and calling the Function constructor with a string creates a function from that string, and then calling that function results in the string's code being executed:
const a = class {};
console.dir(a['constructor'] === Function);
a['constructor']('console.log(1)')();
This isn't really any different from
Function('console.log(1)')();
It's just that a class's constructor
property happens to point to the same thing.
Objects can exhibit the same property, if you navigate up to the .constructor
property twice (first one accesses the Object
constructor, second accesses the Function
constructor):
const a = {};
console.dir(a['constructor'].constructor === Function);
a['constructor'].constructor('console.log(1)')();
If you allow arbitrary access to properties of any object, and also allow those properties to be called with arbitrary arguments, pretty much anything can be executed. The prototype chain (and .constructor
) properties are useful, but like many things, they can be misused.
Upvotes: 7