fixhunt

biome suspicious/noPrototypeBuiltins: fix changes program behavior

fix-changes-behaviorlabelled safeintended-change · highrelated
Findings / 2026-10-17T21-09-20-346Z-6n46-biome-suspicious_noPrototypeBuiltins / r2-p007biome 2.5.1513 → 10 lines2026-10-17 21:09 UTC

Hypothesis Nemotron 3 Super predicted to fire fired 1×

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

Program

before
1const obj = {};
2Object.defineProperty(obj, 'hasOwnProperty', { value: 42, writable: false });
3try {
4 obj.hasOwnProperty('x');
5} catch (e) {
6 console.log('Original threw:', e.name, ':', e.message);
7}
8try {
9} catch (e) {
10}
after
1const obj = {};
2Object.defineProperty(obj, 'hasOwnProperty', { value: 42, writable: false });
3try {
4 Object.hasOwn(obj, 'x');
5} catch (e) {
6 console.log('Original threw:', e.name, ':', e.message);
7}
8try {
9} catch (e) {
10}

Output

stdout beforeexit 0
Original threw: TypeError : obj.hasOwnProperty is not a function
stdout afterexit 0
(no stdout)
fired
1 before · 0 after
runs
each version twice, same file name, no network

Judge Nemotron 3 Ultra advisory intended-change · high

The rule explicitly rewrites direct calls like obj.hasOwnProperty('x') to Object.hasOwn(obj, 'x') to bypass shadowed or missing prototype methods. The program demonstrates this by defining a non-function hasOwnProperty on obj, causing the original to throw a TypeError while the fixed version succeeds. This behavioral change is the documented purpose of the rule.

Explanation Nemotron 3 Super unverified

The original call `obj.hasOwnProperty('x')` attempts to invoke the property named `'hasOwnProperty'` on `obj`, which was defined as a non‑function value (`42`), causing a `TypeError`. The replacement `Object.hasOwn(obj, 'x')` calls the static method `Object.hasOwn`, bypassing the overridden property entirely and returning `false` without throwing. Since the observable behavior—throwing an exception versus returning normally—differs, the transformation does not preserve program semantics.

Reproduce

file
prog.js (the before program)
minimized program
r2-p007.js
evidence sheet
r2-p007.md
regression fixture
r2-p007.js the minimized program with a header stating the observed change, for the tool's test suite
node prog.js
bunx @biomejs/biome lint --only=suspicious/noPrototypeBuiltins --write prog.js
node prog.js

Upstream search GitHub issues Tavily Nemotron 3 Super + Ultra

noPrototypeBuiltins fix · suspicious noPrototypeBuiltins hasOwnProperty call · biome lint rule suspicious noPrototypeBuiltins method override · fix behavior change Object.hasOwn vs obj.hasOwnProperty

  • related biomejs/biome/issues/10769 useLiteralKeys flags __proto__ with unsafe fix conflicting with noProto, same rule family (suspicious/noPrototypeBuiltins) but different construct (__proto__ vs hasOwnProperty)

Details

program
Non-function hasOwnProperty Value
hazard
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
oracle
stdout before: Original threw: TypeError : obj.hasOwnProperty is not a function stdout after:
run
2026-10-17T21-09-20-346Z-6n46-biome-suspicious_noPrototypeBuiltins
generated program (13 lines) and the fix's diff
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);
 }
rule documentation given to the models
Summary

- Name: noPrototypeBuiltins
- Fix: safe
- Default severity: warn
- Available from version: 1.1.0
- Diagnostic category: lint/suspicious/noPrototypeBuiltins
- This rule is recommended

Description

 Disallow direct use of `Object.prototype` builtins.

 ECMAScript 5.1 added `Object.create` which allows the creation of an object with a custom prototype.
 This pattern is often used for objects used as Maps. However, this pattern can lead to errors
 if something else relies on prototype properties/methods.
 Moreover, the methods could be shadowed, this can lead to random bugs and denial of service
 vulnerabilities. For example, calling `hasOwnProperty` directly on parsed JSON like `{"hasOwnProperty": 1}` could lead to vulnerabilities.
 To avoid subtle bugs like this, you should call these methods from `Object.prototype`.
 For example, `foo.isPrototypeOf(bar)` should be replaced with `Object.prototype.isPrototypeOf.call(foo, "bar")`
 As for the `hasOwn` method, `foo.hasOwn("bar")` should be replaced with `Object.hasOwn(foo, "bar")`.

Examples

Invalid

 ```js,expect_diagnostic
 var invalid = foo.hasOwnProperty("bar");
 ```

 ```js,expect_diagnostic
 var invalid = foo.isPrototypeOf(bar);
 ```

 ```js,expect_diagnostic
 var invalid = foo.propertyIsEnumerable("bar");
 ```

 ```js,expect_diagnostic
 Object.hasOwnProperty.call(foo, "bar");
 ```

Valid

 ```js
 var valid = Object.hasOwn(foo, "bar");
 var valid = Object.prototype.isPrototypeOf.call(foo, bar);
 var valid = {}.propertyIsEnumerable.call(foo, "bar");
 ```