eval.toString().length matches the engine (V8 = 33)
Check id etsl
What an ordinary browser yields
A Chrome UA with eval.toString().length === 33, or a non-Chrome UA (check reports N/A).
What a detector infers
The string a JS engine returns for a native function's source is an implementation detail, and its length differs per engine: eval.toString().length is 33 on V8 and 37 on Gecko and WebKit. The check reads that length and — this is the important design choice — gates on the CLAIMED UA rather than on window.chrome or any other engine probe. If the UA carries a Chrome/ token, V8's 33 is required; if it does not, the check returns N/A and is not scored. That framing is what gives it force: a non-V8 engine wearing a Chrome UA fails here even if it has scrubbed every obvious Chrome marker, because the number is produced by the engine's own stringifier deep below the property surface a spoof normally reaches. Severity is critical — the signal is a one-integer read with no plausible false-positive on a genuine Chrome.
How to resolve it
Present a UA that matches the engine you are actually running. If you need a Chrome identity, run a Blink/V8 build — this value is not something to patch at the JS layer, since the same divergence resurfaces across every other native's stringification.
Read in the wild by
Kasada
Ships the entire eval.toString() string verbatim as probe field "evts" (and JSON.stringify's as "jsts"), plus a boolean recording whether that string matches a native-code template built from the engine's own Error.toString(). Kasada stores the whole string rather than its length.
2.txt:43061-43069 — r9 = globalThis["window"]; r8 = r9["eval"]; r5 = _7434(r8, "eval"); r4["ev"] = r5; r5 = _7433["raw"]; r6 = globalThis["window"]; r9 = r6["eval"]; r2 = r9.toString(); r5["evts"] = r2; — inside func_02a68e, which returns {verdict, raw, error} after `r2 = r6.stringify(_7433.raw); r4["raw"] = r2`. Same probe at 3.txt:32953 in a second ips.js version; "evts" also present in both __strTable string caches.
PerimeterX / HUMAN
Collects eval.toString().length as a plain integer, and the same bundle carries a second, separately-keyed probe reading that number via string coercion.
EV2 field "Z1dSXSI3UWg=" = 33 (type number, via "plain") in the captured iFood payload — all_fields_map.json line 922, whose entry records bundle line 7166. Produced by `function Bd(){try{return hS[hQ(694)][hQ(247)]()[hQ(155)]}catch(t){}}` in stample/ifood/source/main.min.js, where hS=window and, per the corpus string table hQ_map.json, hQ(694)="eval", hQ(247)="toString", hQ(155)="length" — i.e. eval.toString().length. The same bundle registers a second probe `{name:"BhYzXEN3NWg=",func:function(){return DX()}}` with `function DX(){return hQ(694)in hS?(eval+"").length:-1}` (that key does not appear in this particular capture).
Every attribution traces to a published artifact. See the sources and their limits.
Nearby checks in Navigator identity
- UA-CH high-entropy hints cohere with the UA
uach-highentropyThis awaits navigator.userAgentData.getHighEntropyValues and compares the richer hints against the UA string on three axes, collecting every… - every brand in a UA-CH list uses the same version format
uach-brand-version-arityUA-CH publishes the same brand set twice at two precisions. navigator.userAgentData.brands carries bare majors like "148", and the… - navigator.language === languages[0]
languages-coherenceIn a real browser navigator.language is defined as the first element of navigator.languages — one preference list, two views onto it. - the host voice roster represents the language the browser claims
locale-vs-voice-coherenceThe voice roster is installed at the operating-system level and the language preference is set in the browser, so the two are genuinely… - navigator.productSub === 20030107 (Chromium)
product-subnavigator.productSub is a frozen legacy constant, not a live value: Chrome, Safari and Opera return "20030107" while Firefox returns… - a Firefox user-agent reports the Gecko productSub constant 20100101
gecko-productsub-hardcodenavigator.productSub is a constant compiled into the engine, and the two families disagree: every Gecko build hardcodes it to "20100101"… - navigator.deviceMemory is a power-of-two spec value
device-memory-boundsnavigator.deviceMemory does not report actual RAM — the spec requires the UA to quantise it to a coarse power-of-two rung before exposing… - navigator.hardwareConcurrency is plausible
hardware-concurrencyThis is an info-severity observation, not a scored failure — it reports navigator.hardwareConcurrency and only notes whether the value is an…
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 Navigator identity 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 Navigator identity — the family etsl belongs to.