Prototype Method Access
ID |
javascript.prototype_method_access |
Severity |
low |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
JavaScript |
Tags |
best-practice, prototype, reliability |
Description
Reports a call to one of the Object.prototype builtins — hasOwnProperty, isPrototypeOf, propertyIsEnumerable — through an instance receiver.
if (record.hasOwnProperty("id")) { } // FLAW
if (base.isPrototypeOf(derived)) { } // FLAW
A call written through .call is not matched: its callee is call, not the builtin, and going through Function.prototype.call is precisely the safe spelling. A receiver that is itself a .prototype access is left alone for the same reason.
Rationale
The receiver is not guaranteed to have the method.
-
An object built with
Object.create(null)— the standard way to make a dictionary that cannot collide with inherited names — has no prototype at all, so the call throws aTypeError. -
Any object parsed from JSON can carry a property literally named
hasOwnProperty, which shadows the builtin. The call then runs the data’s value instead of the check, and returns whatever that value returns.
Both failures land on exactly the objects the check exists to inspect — untrusted input and dictionaries — which is what makes the shorthand worth replacing rather than tolerating.
Remediation
Use Object.hasOwn, or call the builtin through Object.prototype.
if (Object.hasOwn(record, "id")) { }
if (Object.prototype.hasOwnProperty.call(record, "id")) { }
if (Object.prototype.isPrototypeOf.call(base, derived)) { }
Where the check is guarding a lookup, a Map avoids the question altogether: its keys never collide with prototype names.