The vulnerability is a sandbox escape caused by improper handling of property access and assignment checks. The root cause is the direct use of the hasOwnProperty method on objects that can be controlled by code running inside the sandbox. An attacker can create an object with a custom hasOwnProperty method that always returns a predictable value (e.g., true or false). This allows bypassing security checks that rely on hasOwnProperty to distinguish between an object's own properties and inherited properties from its prototype.
The analysis of the patch 67cb186c41c78c51464f70405504e8ef0a6e43c3 reveals several vulnerable functions where this pattern occurs:
-
propAccessHandler (anonymous function in src/executor.ts): This function determines whether to enforce prototype access restrictions. By shadowing hasOwnProperty to return true, an attacker can make the prototypeAccess flag false, effectively disabling the prototype whitelist and gaining access to __proto__, which leads to prototype pollution.
-
assignCheck (in src/executor.ts): This function checks if an assignment is attempting to override a prototype method. This check is also bypassed by shadowing hasOwnProperty, allowing the attacker to modify the prototype of host objects.
-
Scope.get and Scope.declare (in src/utils.ts): These methods, responsible for variable lookup and declaration, also used unsafe hasOwnProperty calls on context-related objects. This could be exploited to interfere with variable management within the sandbox.
The fix applied in the patch is to replace all direct calls to obj.hasOwnProperty(prop) with a safe utility function hasOwnProperty(obj, prop) which is defined as Object.prototype.hasOwnProperty.call(obj, prop). This ensures that the original, un-tampered hasOwnProperty method is always used, preventing the sandbox escape.