biome suspicious/noPrototypeBuiltins
labelled safe
Analysis Nemotron 3 Super
Flags direct calls to Object.prototype methods (hasOwnProperty, isPrototypeOf, propertyIsEnumerable) invoked on arbitrary objects.
Fix: Replaces obj.methodName(args) with Object.prototype.methodName.call(obj, args) for hasOwnProperty, isPrototypeOf, and propertyIsEnumerable; replaces obj.hasOwnProperty with Object.hasOwn when applicable per rule documentation.
11 hazards
- Rewriting foo.hasOwnProperty("bar") to Object.prototype.hasOwnProperty.call(foo, "bar") changes behavior if foo is null or undefined, as the former throws a TypeError while the latter also throws but may be caught differently due to call stack differences.
- If foo.hasOwnProperty is a non-function value (e.g., a number or string), the original code throws TypeError when invoked, but the fix attempts to call Object.prototype.hasOwnProperty.call which expects a function, preserving the error but altering the error path.
- When foo is declared with let or const and used before initialization in the same block, the fix does not alter the TDZ error timing, but if the original relied on foo being accessible via a scope hole, the fix does not change that—however, no behavioral shift occurs here as both forms reference foo identically.
- If foo is a proxy with a get trap that returns a non-function for hasOwnProperty, the original invokes the trap and then attempts to call the result, throwing TypeError; the fix bypasses the trap entirely by referencing Object.prototype directly, so the get trap is not triggered, altering observable behavior.
- In strict mode, if foo.hasOwnProperty is accessed via a with statement (deprecated but possible), the original resolves foo in the with scope, while the fix references Object.prototype globally, potentially changing the base object if the with scope had an Object property.
- The fix removes any opportunity for side effects in the retrieval of foo.hasOwnProperty—such as logging in a get trap or modifying state—because it no longer accesses the property on foo at all, whereas the original evaluates foo.hasOwnProperty as an expression before calling it.
- If the code depends on the call stack showing foo.hasOwnProperty in traces (e.g., for debugging or error reporting), replacing it with Object.prototype.hasOwnProperty.call alters the stack trace, which could affect error handling logic that inspects stack frames.
- When the argument "bar" is an expression with side effects (e.g., a function call), the evaluation order of arguments is preserved in the fix, but if the original relied on the this-value being evaluated after arguments (which it never is in JS), no change occurs—however, this is not a real hazard since this-binding always happens before argument evaluation in calls.
- If foo is document.all in legacy browsers (which acts like undefined for == null but has special behavior), the original may behave inconsistently due to its [[Call]] semantics, while the fix uses standard Function.prototype.call, potentially altering behavior in edge cases involving IE-specific quirks.
- If the code is parsed in a context where Object.prototype has been overridden (e.g., via iframe pollution or deliberate mutation), the fix uses the current Object.prototype, which may differ from the original object's actual prototype chain if inheritance was altered, though this affects both original and fix similarly since both rely on Object.prototype.
- Comments attached to the original call site (e.g., foo.hasOwnProperty/*note*/("bar")) may be lost or misplaced during the rewrite if the autofix does not preserve trailing or inline comments, degrading code readability.
Findings
| program | oracle | label | judge | status | summary |
|---|---|---|---|---|---|
| r1-p007 | fix-changes-behavior | labelled safe | intended-change · high | related | The program deliberately shadows hasOwnProperty on obj with a non-function value (42). The rule exists precisely to bypass such shadowing by rewriting obj.hasO… |
| r2-p007 | fix-changes-behavior | labelled safe | intended-change · high | related | The rule explicitly rewrites direct calls like obj.hasOwnProperty('x') to Object.hasOwn(obj, 'x') to bypass shadowed or missing prototype methods. The program … |
| r1-p002 | fix-changes-behavior | labelled safe | intended-change · low | related | The rule rewrites foo.hasOwnProperty('x') to Object.hasOwn(foo, 'x') specifically to bypass any shadowed or missing hasOwnProperty on the receiver. The origina… |
| r1-p006 | fix-changes-behavior | labelled safe | intended-change · low | related | The rule rewrites `fakeAll.hasOwnProperty('length')` to `Object.hasOwn(fakeAll, 'length')` to bypass any shadowed `hasOwnProperty` method. The program delibera… |
| r2-p001 | fix-changes-behavior | labelled safe | intended-change · low | related | The rule intentionally replaces direct prototype method calls with static Object.hasOwn to avoid shadowing vulnerabilities. The original code threw a TypeError… |
| r2-p002 | fix-changes-behavior | labelled safe | intended-change · low | related | The rule explicitly warns that prototype methods like hasOwnProperty can be shadowed and replaces direct calls with Object.hasOwn to bypass the object's own pr… |
| r2-p005 | fix-changes-behavior | labelled safe | intended-change · low | related | The rule explicitly rewrites direct calls like obj.hasOwnProperty('foo') to Object.hasOwn(obj, 'foo') to bypass any shadowed or custom hasOwnProperty on the ob… |
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | fix ok | Order of Evaluation - Side Effects Duplicated | order of evaluation when expressions are merged, duplicated or deleted (side effects run twice or never) |
| r1-p002 | fix-changes-behavior prediction off | Temporal Dead Zone After Hoisting | temporal dead zone after code is hoisted or reordered |
| r1-p003 | fix ok | TDZ Error Timing Unchanged by Fix | When foo is declared with let or const and used before initialization in the same block, the fix does not alter the TDZ error timing... |
| r1-p004 | fix ok | Numeric/String Coercion | numeric/string coercion: + vs template literal, objects with toString/valueOf, Symbol, BigInt |
| r1-p005 | fix ok | __proto__ Keys and Prototype Access | __proto__ keys, prototype access, Object.assign vs spread |
| r1-p006 | fix-changes-behavior | document.all Legacy Quirk | If foo is document.all in legacy browsers [...] potentially altering behavior in edge cases involving IE-specific quirks. |
| r1-p007 | fix-changes-behavior | Non-Function hasOwnProperty Value | If foo.hasOwnProperty is a non-function value (e.g., a number or string), the original code throws TypeError when invoked, but the fix attempts to call Object.prototype.hasOwnProperty.call which expec |
| r1-p008 | fix ok | this Binding: Arrow vs Function | this binding: arrow vs function, methods extracted from objects, call/apply/bind |
| r2-p001 | fix-changes-behavior | Null/undefined Distinction with Optional Chaining | null/undefined distinction, optional chaining short-circuit, nullish vs falsy |
| r2-p002 | fix-changes-behavior | Getter Side Effect via DefineProperty | getters, setters and Object.defineProperty side effects |
| r2-p003 | fix ok | Async Await Interaction with Property Access | async/await ordering, generators and yield position |
| r2-p004 | fix ok | Order of Evaluation - Side Effects Doubled | order of evaluation when expressions are merged, duplicated or deleted (side effects run twice or never) |
| r2-p005 | fix-changes-behavior | Property Access Trap Side Effect Lost | The fix removes any opportunity for side effects in the retrieval of foo.hasOwnProperty—such as logging in a get trap or modifying state—because it no longer accesses the property on foo at all, where |
| r2-p006 | fix ok | Argument Evaluation Order Preserved | When the argument "bar" is an expression with side effects (e.g., a function call), the evaluation order of arguments is preserved in the fix, but if the original relied on the this-value being evalua |
| r2-p007 | fix-changes-behavior | Non-function hasOwnProperty Value | If foo.hasOwnProperty is a non-function value (e.g., a number or string), the original code throws TypeError when invoked, but the fix attempts to call Object.prototype.hasOwnProperty.call which expec |
| r2-p008 | fix ok | this Binding: Arrow vs Function Method Extraction | this binding: arrow vs function, methods extracted from objects, call/apply/bind |
Sources
r1-p001 · Order of Evaluation - Side Effects Duplicated
1let counter = 0;
2function getKey() {
3 return ++counter;
4}
5const obj = {};
6try {
7 console.log(obj[getKey()] = 'first', obj.hasOwnProperty(getKey()));
8} catch (e) {
9 console.log(e.name, e.message);
10}
--- orig.js 2026-10-17 17:09:33.367972158 -0400 +++ fixed.js 2026-10-17 17:09:33.654975164 -0400 @@ -4,7 +4,7 @@ } const obj = {}; try { - console.log(obj[getKey()] = 'first', obj.hasOwnProperty(getKey())); + console.log(obj[getKey()] = 'first', Object.hasOwn(obj, getKey())); } catch (e) { console.log(e.name, e.message); }
first false
r1-p002 · Temporal Dead Zone After Hoisting
1if (typeof foo === 'undefined') {
2 try {
3 console.log(foo.hasOwnProperty('x'));
4 } catch (e) {
5 console.log(e.name, e.message);
6 }
7}
8var foo = { x: 1 };
--- orig.js 2026-10-17 17:09:33.828976986 -0400 +++ fixed.js 2026-10-17 17:09:34.111979950 -0400 @@ -1,6 +1,6 @@ if (typeof foo === 'undefined') { try { - console.log(foo.hasOwnProperty('x')); + console.log(Object.hasOwn(foo, 'x')); } catch (e) { console.log(e.name, e.message); }
TypeError Cannot read properties of undefined (reading 'hasOwnProperty')
r1-p003 · TDZ Error Timing Unchanged by Fix
1{
2 try {
3 console.log(value.hasOwnProperty('a'));
4 } catch (e) {
5 console.log(e.name, e.message);
6 }
7 const value = {};
8}
--- orig.js 2026-10-17 17:09:34.282981741 -0400 +++ fixed.js 2026-10-17 17:09:34.565984705 -0400 @@ -1,6 +1,6 @@ { try { - console.log(value.hasOwnProperty('a')); + console.log(Object.hasOwn(value, 'a')); } catch (e) { console.log(e.name, e.message); }
ReferenceError Cannot access 'value' before initialization
r1-p004 · Numeric/String Coercion
1const obj = {
2 [Symbol.toPrimitive](hint) { return hint === 'string' ? 'prop' : 42; }
3};
4console.log(obj.hasOwnProperty('prop'), obj.hasOwnProperty(42));
5console.log(Object.prototype.hasOwnProperty.call(obj, 'prop'), Object.prototype.hasOwnProperty.call(obj, 42));
--- orig.js 2026-10-17 17:09:34.738986516 -0400 +++ fixed.js 2026-10-17 17:09:35.001989271 -0400 @@ -1,5 +1,5 @@ const obj = { [Symbol.toPrimitive](hint) { return hint === 'string' ? 'prop' : 42; } }; -console.log(obj.hasOwnProperty('prop'), obj.hasOwnProperty(42)); -console.log(Object.prototype.hasOwnProperty.call(obj, 'prop'), Object.prototype.hasOwnProperty.call(obj, 42)); +console.log(Object.hasOwn(obj, 'prop'), Object.hasOwn(obj, 42)); +console.log(Object.hasOwn(obj, 'prop'), Object.hasOwn(obj, 42));
false false false false
r1-p005 · __proto__ Keys and Prototype Access
1const obj = { __proto__: { toString: 1 }, toString: 'own' };
2console.log(obj.hasOwnProperty('toString'));
3console.log(Object.prototype.hasOwnProperty.call(obj, 'toString'));
--- orig.js 2026-10-17 17:09:35.180991145 -0400 +++ fixed.js 2026-10-17 17:09:35.451993982 -0400 @@ -1,3 +1,3 @@ const obj = { __proto__: { toString: 1 }, toString: 'own' }; -console.log(obj.hasOwnProperty('toString')); -console.log(Object.prototype.hasOwnProperty.call(obj, 'toString')); +console.log(Object.hasOwn(obj, 'toString')); +console.log(Object.hasOwn(obj, 'toString'));
true true
r1-p006 · document.all Legacy Quirk
1// Simulating document.all-like object
2const fakeAll = {
3 [Symbol.isConcatSpreadable]: true,
4 toString: () => '',
5 valueOf: () => undefined
6};
7fakeAll.__proto__ = null;
8try {
9 console.log(fakeAll == null, fakeAll.hasOwnProperty('length'));
10} catch (e) {
11 console.log(e.name, e.message);
12}
13try {
14 console.log(fakeAll == null, Object.prototype.hasOwnProperty.call(fakeAll, 'length'));
15} catch (e) {
16 console.log(e.name, e.message);
17}
--- orig.js 2026-10-17 17:09:35.623995783 -0400 +++ fixed.js 2026-10-17 17:09:35.909998778 -0400 @@ -6,12 +6,12 @@ }; fakeAll.__proto__ = null; try { - console.log(fakeAll == null, fakeAll.hasOwnProperty('length')); + console.log(fakeAll == null, Object.hasOwn(fakeAll, 'length')); } catch (e) { console.log(e.name, e.message); } try { - console.log(fakeAll == null, Object.prototype.hasOwnProperty.call(fakeAll, 'length')); + console.log(fakeAll == null, Object.hasOwn(fakeAll, 'length')); } catch (e) { console.log(e.name, e.message); }
TypeError fakeAll.hasOwnProperty is not a function false false
r1-p007 · Non-Function hasOwnProperty Value
1const obj = {};
2Object.defineProperty(obj, 'hasOwnProperty', { value: 42, writable: false });
3try {
4 console.log(obj.hasOwnProperty('x'));
5} catch (e) {
6 console.log(e.name, e.message);
7}
8try {
9 console.log(Object.prototype.hasOwnProperty.call(obj, 'x'));
10} catch (e) {
11 console.log(e.name, e.message);
12}
--- orig.js 2026-10-17 17:09:36.086000620 -0400 +++ fixed.js 2026-10-17 17:09:36.357003457 -0400 @@ -1,12 +1,12 @@ const obj = {}; Object.defineProperty(obj, 'hasOwnProperty', { value: 42, writable: false }); try { - console.log(obj.hasOwnProperty('x')); + console.log(Object.hasOwn(obj, 'x')); } catch (e) { console.log(e.name, e.message); } try { - console.log(Object.prototype.hasOwnProperty.call(obj, 'x')); + console.log(Object.hasOwn(obj, 'x')); } catch (e) { console.log(e.name, e.message); }
TypeError obj.hasOwnProperty is not a function false
r1-p008 · this Binding: Arrow vs Function
1const obj = {
2 prop: 'value',
3 check: function() { return this.prop === 'value'; }
4};
5const fn = obj.check;
6console.log(fn());
7try {
8 console.log(obj.hasOwnProperty('check'));
9} catch (e) {
10 console.log(e.name, e.message);
11}
--- orig.js 2026-10-17 17:09:36.522005184 -0400 +++ fixed.js 2026-10-17 17:09:36.782007906 -0400 @@ -5,7 +5,7 @@ const fn = obj.check; console.log(fn()); try { - console.log(obj.hasOwnProperty('check')); + console.log(Object.hasOwn(obj, 'check')); } catch (e) { console.log(e.name, e.message); }
r2-p001 · Null/undefined Distinction with Optional Chaining
1let obj = null;
2console.log('obj == null:', obj == null);
3console.log('obj === null:', obj === null);
4try {
5 console.log(obj?.hasOwnProperty('prop'));
6} catch (e) {
7 console.log('Optional chain threw:', e.name, e.message);
8}
9try {
10 console.log(obj.hasOwnProperty('prop'));
11} catch (e) {
12 console.log('Direct call threw:', e.name, e.message);
13}
--- orig.js 2026-10-17 17:09:45.244096410 -0400 +++ fixed.js 2026-10-17 17:09:45.521099305 -0400 @@ -7,7 +7,7 @@ console.log('Optional chain threw:', e.name, e.message); } try { - console.log(obj.hasOwnProperty('prop')); + console.log(Object.hasOwn(obj, 'prop')); } catch (e) { console.log('Direct call threw:', e.name, e.message); }
obj == null: true obj === null: true undefined Direct call threw: TypeError Cannot read properties of null (reading 'hasOwnProperty')
r2-p002 · Getter Side Effect via DefineProperty
1const obj = {};
2Object.defineProperty(obj, 'hasOwnProperty', {
3 get() {
4 console.log('Getter called');
5 return Object.prototype.hasOwnProperty;
6 }
7});
8console.log('Before:');
9obj.hasOwnProperty('x');
10console.log('After:');
--- orig.js 2026-10-17 17:09:45.699101165 -0400 +++ fixed.js 2026-10-17 17:09:45.977104070 -0400 @@ -6,5 +6,5 @@ } }); console.log('Before:'); -obj.hasOwnProperty('x'); +Object.hasOwn(obj, 'x'); console.log('After:');
Before: Getter called After:
r2-p003 · Async Await Interaction with Property Access
1async function test() {
2 const obj = { awaitPromise: Promise.resolve(42) };
3 console.log('Start');
4 try {
5 const val = await obj.hasOwnProperty('awaitPromise');
6 console.log('Result:', val);
7 } catch (e) {
8 console.log('Caught:', e.name);
9 }
10}
11test().then(() => console.log('Done'));
--- orig.js 2026-10-17 17:09:46.149105867 -0400 +++ fixed.js 2026-10-17 17:09:46.407108563 -0400 @@ -2,7 +2,7 @@ const obj = { awaitPromise: Promise.resolve(42) }; console.log('Start'); try { - const val = await obj.hasOwnProperty('awaitPromise'); + const val = await Object.hasOwn(obj, 'awaitPromise'); console.log('Result:', val); } catch (e) { console.log('Caught:', e.name);
Start Result: true Done
r2-p004 · Order of Evaluation - Side Effects Doubled
1let count = 0;
2function logArg() {
3 console.log('arg eval', ++count);
4 return 'key';
5}
6const obj = {};
7console.log('Before fix simulation:');
8const prop = obj.hasOwnProperty;
9prop.call(obj, logArg());
10count = 0;
11console.log('\nAfter fix (Biome rewrites):');
12Object.prototype.hasOwnProperty.call(obj, logArg());
--- orig.js 2026-10-17 17:09:46.574110307 -0400 +++ fixed.js 2026-10-17 17:09:46.852113212 -0400 @@ -9,4 +9,4 @@ prop.call(obj, logArg()); count = 0; console.log('\nAfter fix (Biome rewrites):'); -Object.prototype.hasOwnProperty.call(obj, logArg()); +Object.hasOwn(obj, logArg());
Before fix simulation: arg eval 1 After fix (Biome rewrites): arg eval 1
r2-p005 · Property Access Trap Side Effect Lost
1let accessCount = 0;
2const handler = {
3 get(target, prop) {
4 accessCount++;
5 if (prop === 'hasOwnProperty') {
6 console.log('Trap hit for hasOwnProperty, access #', accessCount);
7 return Object.prototype.hasOwnProperty;
8 }
9 return target[prop];
10 }
11};
12const obj = new Proxy({ foo: 1 }, handler);
13accessCount = 0;
14console.log('Before (original):');
15obj.hasOwnProperty('foo');
16console.log('Access count after original:', accessCount);
17accessCount = 0;
18console.log('\nAfter (fixed):');
19Object.prototype.hasOwnProperty.call(obj, 'foo');
20console.log('Access count after fixed:', accessCount);
--- orig.js 2026-10-17 17:09:47.033115103 -0400 +++ fixed.js 2026-10-17 17:09:47.306117955 -0400 @@ -12,9 +12,9 @@ const obj = new Proxy({ foo: 1 }, handler); accessCount = 0; console.log('Before (original):'); -obj.hasOwnProperty('foo'); +Object.hasOwn(obj, 'foo'); console.log('Access count after original:', accessCount); accessCount = 0; console.log('\nAfter (fixed):'); -Object.prototype.hasOwnProperty.call(obj, 'foo'); +Object.hasOwn(obj, 'foo'); console.log('Access count after fixed:', accessCount);
Before (original): Trap hit for hasOwnProperty, access # 1 Access count after original: 1 After (fixed): Access count after fixed: 0
r2-p006 · Argument Evaluation Order Preserved
1let order = [];
2function sideEffect(label) {
3 return () => {
4 order.push(label);
5 return label;
6 };
7}
8const obj = { a: 1 };
9order = [];
10console.log('Original evaluation order:');
11obj.hasOwnProperty(sideEffect('first')());
12console.log('Order:', order.join(' -> '));
13order = [];
14console.log('\nFixed evaluation order:');
15Object.prototype.hasOwnProperty.call(obj, sideEffect('first')());
16console.log('Order:', order.join(' -> '));
--- orig.js 2026-10-17 17:09:47.475119720 -0400 +++ fixed.js 2026-10-17 17:09:47.763122729 -0400 @@ -8,9 +8,9 @@ const obj = { a: 1 }; order = []; console.log('Original evaluation order:'); -obj.hasOwnProperty(sideEffect('first')()); +Object.hasOwn(obj, sideEffect('first')()); console.log('Order:', order.join(' -> ')); order = []; console.log('\nFixed evaluation order:'); -Object.prototype.hasOwnProperty.call(obj, sideEffect('first')()); +Object.hasOwn(obj, sideEffect('first')()); console.log('Order:', order.join(' -> '));
Original evaluation order: Order: first Fixed evaluation order: Order: first
r2-p007 · Non-function hasOwnProperty Value
1const obj = {};
2Object.defineProperty(obj, 'hasOwnProperty', { value: 42, writable: false });
3console.log('obj.hasOwnProperty:', obj.hasOwnProperty);
4try {
5 obj.hasOwnProperty('x');
6} catch (e) {
7 console.log('Original threw:', e.name, ':', e.message);
8}
9try {
10 Object.prototype.hasOwnProperty.call(obj, 'x');
11} catch (e) {
12 console.log('Fixed threw:', e.name, ':', e.message);
13}
--- orig.js 2026-10-17 17:09:47.930124473 -0400 +++ fixed.js 2026-10-17 17:09:48.201127303 -0400 @@ -2,12 +2,12 @@ Object.defineProperty(obj, 'hasOwnProperty', { value: 42, writable: false }); console.log('obj.hasOwnProperty:', obj.hasOwnProperty); try { - obj.hasOwnProperty('x'); + Object.hasOwn(obj, 'x'); } catch (e) { console.log('Original threw:', e.name, ':', e.message); } try { - Object.prototype.hasOwnProperty.call(obj, 'x'); + Object.hasOwn(obj, 'x'); } catch (e) { console.log('Fixed threw:', e.name, ':', e.message); }
obj.hasOwnProperty: 42 Original threw: TypeError : obj.hasOwnProperty is not a function
r2-p008 · this Binding: Arrow vs Function Method Extraction
1const obj = {
2 value: 42,
3 check: function() {
4 return this.value === 42;
5 },
6 checkArrow: () => {
7 return this.value === 42;
8 }
9};
10const fn = obj.check;
11const arrowFn = obj.checkArrow;
12console.log('Function method call:', obj.check());
13console.log('Extracted function call:', fn());
14console.log('Arrow method call:', obj.checkArrow());
15console.log('Extracted arrow call:', arrowFn());
16try {
17 obj.hasOwnProperty('value');
18} catch (e) {
19 console.log('hasOwnProperty call failed:', e.name);
20}
--- orig.js 2026-10-17 17:09:48.370129069 -0400 +++ fixed.js 2026-10-17 17:09:48.651132003 -0400 @@ -14,7 +14,7 @@ console.log('Arrow method call:', obj.checkArrow()); console.log('Extracted arrow call:', arrowFn()); try { - obj.hasOwnProperty('value'); + Object.hasOwn(obj, 'value'); } catch (e) { console.log('hasOwnProperty call failed:', e.name); }
Function method call: true