fixhunt

biome suspicious/noPrototypeBuiltins: fix changes program behavior

fix-changes-behaviorlabelled safeintended-change · lowrelated
Findings / 2026-10-17T21-09-20-346Z-6n46-biome-suspicious_noPrototypeBuiltins / r1-p006biome 2.5.1517 → 7 lines2026-10-17 21:09 UTC

Hypothesis Nemotron 3 Super predicted to fire fired 1×

If foo is document.all in legacy browsers [...] potentially altering behavior in edge cases involving IE-specific quirks.

Program

before
1const fakeAll = {
2};
3fakeAll.__proto__ = null;
4try {
5 console.log(fakeAll == null, fakeAll.hasOwnProperty('length'));
6} catch (e) {
7}
after
1const fakeAll = {
2};
3fakeAll.__proto__ = null;
4try {
5 console.log(fakeAll == null, Object.hasOwn(fakeAll, 'length'));
6} catch (e) {
7}

Output

stdout beforeexit 0
(no stdout)
stdout afterexit 0
false false
fired
1 before · 0 after
runs
each version twice, same file name, no network

Judge Nemotron 3 Ultra advisory intended-change · low

The rule rewrites `fakeAll.hasOwnProperty('length')` to `Object.hasOwn(fakeAll, 'length')` to bypass any shadowed `hasOwnProperty` method. The program deliberately sets `__proto__ = null` so the object lacks the built-in method; the original call throws and is caught, producing no output, while the fixed call succeeds and prints `false false`. This behavioral change is exactly what the rule documents as its purpose.

Explanation Nemotron 3 Super unverified

The original call `fakeAll.hasOwnProperty('length')` uses the inherited method from `Object.prototype`, but since `__proto__` is set to `null`, `fakeAll` has no prototype chain, so accessing `.hasOwnProperty` throws a TypeError because the property is undefined. This error is caught, so nothing is printed. The fix replaces it with `Object.hasOwn(fakeAll, 'length')`, which is a standalone function that does not rely on the object’s prototype and safely returns `false`. Thus, the try block now executes fully, printing `false false` instead of catching an error and printing nothing. The behavior changes because the fix avoids a thrown exception that was previously silenced.

Reproduce

file
prog.js (the before program)
minimized program
r1-p006.js
evidence sheet
r1-p006.md
regression fixture
r1-p006.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 · Object.hasOwn replacement pattern · prototype null object property check

  • related biomejs/biome/issues/10769 useLiteralKeys flags __proto__ in computed member expression with unsafe fix conflicting with noProto, same rule domain but different construct

Details

program
document.all Legacy Quirk
hazard
If foo is document.all in legacy browsers [...] potentially altering behavior in edge cases involving IE-specific quirks.
oracle
stdout before: stdout after: false false
run
2026-10-17T21-09-20-346Z-6n46-biome-suspicious_noPrototypeBuiltins
generated program (17 lines) and the fix's diff
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);
 }
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");
 ```