# biome suspicious/noPrototypeBuiltins: fix changes program behavior

Internal evidence sheet generated by fixhunt. Not an issue text. A human re-verifies, checks the duplicates
below, and writes the upstream report in their own words following the project's AI policy.

- Tool: biome 2.5.15
- Rule: suspicious/noPrototypeBuiltins (tool labels the fix: safe, this fix reported as safe)
- Oracle: fix-changes-behavior
- Judge (Nemotron 3 Ultra, advisory): intended-change, severity low. The rule explicitly rewrites direct calls like obj.hasOwnProperty('foo') to Object.hasOwn(obj, 'foo') to bypass any shadowed or custom hasOwnProperty on the object. The program demonstrates this by using a Proxy that traps access to hasOwnProperty; the fix intentionally avoids that trap, changing the observable behavior exactly as the documentation describes.
- Program: minimized from 20 to 11 lines

## Reproducer

```js
let accessCount = 0;
const handler = {
  get(target, prop) {
    if (prop === 'hasOwnProperty') {
      console.log('Trap hit for hasOwnProperty, access #', accessCount);
    }
    return target[prop];
  }
};
const obj = new Proxy({ foo: 1 }, handler);
obj.hasOwnProperty('foo');
```

## Commands

```sh
node prog.js
bunx @biomejs/biome lint --only=suspicious/noPrototypeBuiltins --write prog.js
node prog.js
```

## Observed

```
stdout before:
Trap hit for hasOwnProperty, access # 0
stdout after:
```

## Diff applied by the fix

```diff
--- orig.js	2026-10-22 13:37:00.299611272 -0400
+++ fixed.js	2026-10-22 13:37:02.848654350 -0400
@@ -8,4 +8,4 @@
   }
 };
 const obj = new Proxy({ foo: 1 }, handler);
-obj.hasOwnProperty('foo');
+Object.hasOwn(obj, 'foo');
```

## Why the rewrite is not equivalent (model draft, verify before use)

The original call `obj.hasOwnProperty('foo')` invokes the proxy’s `get` trap because property lookup on `obj` triggers it; when `prop` equals `'hasOwnProperty'`, the trap logs before returning the inherited method. The replacement `Object.hasOwn(obj, 'foo')` is a direct function call that does not access any property on `obj`, so the proxy’s `get` trap is never invoked and no logging occurs. Thus the rewrite changes observable behavior.

## Upstream search

Queries: "noPrototypeBuiltins fix", "suspicious noPrototypeBuiltins proxy trap", "Proxy object hasOwnProperty call", "handler get method interception"

- related: https://github.com/biomejs/biome/issues/10769
  useLiteralKeys flags __proto__ in computed member expression, same rule family (noPrototypeBuiltins) but different construct (computed member vs direct property access)

<details><summary>All hits</summary>

- [github, open] 💅 `useSortedProperties` can produce invalid CSS when the final semicolon is omitted — https://github.com/biomejs/biome/issues/12417
- [github, open] 💅 `useSortedProperties` moves Sass variable declarations below their uses — https://github.com/biomejs/biome/issues/12414
- [github, open] 💅 `useSortedProperties` can change behavior when reordering nested CSS rules — https://github.com/biomejs/biome/issues/12413
- [github, open] 💅 `noUnnecessaryConditions`: false positive on an overloaded call with `undefined` as the default argument (Vue `inject`) — https://github.com/biomejs/biome/issues/12040
- [github, open] 💅 `noSkippedTests` conditionally skip fix suggestion — https://github.com/biomejs/biome/issues/9295
- [github, open] 💅 Actually used private method considered unused — https://github.com/biomejs/biome/issues/8185
- [github, open] 💅 cannot detect that the StrictMode component of React is being exported. — https://github.com/biomejs/biome/issues/10609
- [github, open] 💅 noUnnecessaryConditions callback overload false positive — https://github.com/biomejs/biome/issues/11439
- [github, open] 💅 lint/a11y/useAnchorContent: the PascalCase component allowance is applied only to self-closing elements — https://github.com/biomejs/biome/issues/11872
- [github, open] 💅 useLiteralKeys flags `__proto__` in a computed member expression and offers an unsafe fix that conflicts with noProto — https://github.com/biomejs/biome/issues/10769

</details>
