Natives a spoof rewrites refuse a prototype cycle, as real functions do
Every probed native throws TypeError when given a prototype cycle (severity: warn).
What a detector infers
A common way to rewrite a browser value from script is to wrap the native function or getter that returns it in a Proxy. The Proxy forwards toString to the original, so the usual check (does the function still print as native code?) passes. But a Proxy changes one behaviour that toString does not cover.
JavaScript refuses to give an object a prototype chain that loops back to itself: Object.setPrototypeOf(fn, Object.create(fn)) throws a TypeError ('Cyclic __proto__ value') for every real function. The specification's loop check stops when it reaches a Proxy, so the same call on a Proxy-wrapped native succeeds.
The audit makes that call on up to 27 natives and getters that fingerprint spoofs rewrite (Function.prototype.toString, the navigator and screen getters, canvas, WebGL, audio, time zone, permissions and layout methods) and puts each prototype back straight away. Measured on 2 November 2026 on Windows: genuine Chrome 156 and Clearcote throw on every one. Privacy extensions that wrap natives with a Proxy are caught as well, which is accurate: the wrapper is visible to any page.
How to resolve it
Change values below JavaScript. A Proxy around a native passes toString checks but lets a prototype cycle through, which no real function does; the only way to be identical to a real function is to be one.
Nearby checks in Native function integrity
- Function.toString not proxied (native code)
tostring-nativeThe check stringifies two functions and requires both to match /\{\s*\[native code\]\s*\}/: Function.prototype.toString itself (read as… - Navigator props resolve via native prototype getters
navigator-descriptorsFor deviceMemory, hardwareConcurrency, language, languages and platform, the check reads the property descriptor twice. - Every navigator accessor and method is native, not just the well-known ones
navigator-prototype-fully-nativenavigator-descriptors asks whether seven named properties resolve through native prototype getters. - Key native functions are untampered (toString + no prototype)
native-integrityThis runs a battery over roughly forty engine-owned callables — canvas, WebGL, navigator, iframe, shadow-DOM and fetch natives, plus the JS… - A fresh iframe (contentWindow) matches the main realm
iframe-coherenceThe check appends a hidden same-origin iframe to documentElement and reads its contentWindow — a brand-new JavaScript realm with its own… - Worker navigator matches the main thread
worker-navigator-coherenceA Blob-URL Worker is spawned and reports its own navigator.platform, navigator.hardwareConcurrency, navigator.webdriver and… - Page-world natives that extensions commonly wrap
page-world-wrappersThis probe stringifies window.fetch and window.Request and asks whether each still renders as native code, then checks whether document… - Nonexistent navigator properties return undefined
navigator-proxy-honeypotThis reads five navigator property names that exist on no browser — rml, ln, rnd, webdriverPatched and __clearcoteProbe — and additionally…
Clearcote is a browser built for fingerprint coherence
It is a Chromium fork, maintained by the same people who wrote this reference. It ships as a compiled browser rather than as a stealth script injected into someone else's — which is a description of how it is built, and is not an argument about how it behaves on this check.
This audit takes no position on how Clearcote scores on Native function integrity checks, on this one, or anywhere else. It has no baseline corpus of other people's fingerprints to rank you against and no vendor scoreboard — nearly every check is self-referential, asking one browser the same question through two independent APIs and reporting whether both answers can be true at once. It runs identically on any browser, including ours. Run it on yours and read the result yourself.
See the other checks in Native function integrity — the family native-proxy-cycle-throws belongs to.
