Skip to content
All fingerprint checksNative function integrity

the global object still has every global a fresh realm has, in the same order

Check id window-globals-vs-realm

What an ordinary browser yields

Every global present in a fresh realm is also present here, and the shared names appear in the same relative order. Extra globals on the page are normal and ignored.

What a detector infers

The audit builds a fresh same-origin iframe and enumerates the own properties of both global objects, then asserts two things a browser cannot violate on its own. First, subset: every platform global the pristine realm has must also exist here, because both realms are built from the same blueprint by the same browser. Additions are ignored outright — a real page has plenty, and so do extensions and wallets — but nothing legitimate REMOVES a platform global. Second, order — but on V8 only. V8 emits string-keyed own properties in insertion order and installs a realm's globals in a fixed order at setup, so the names shared by both realms must appear in the same relative sequence. SpiderMonkey does not work this way at all: Gecko resolves standard classes lazily, and the global's enumerate hook reports the still-unresolved names first and appends the already-resolved ones after, so a global sorts to the end merely by having been touched — order there reflects each realm's resolution history rather than a blueprint. Measured on stock Firefox 152 with a fresh profile and a bare page: 980 of 982 shared names out of position. Asserting order on every engine would not catch one extra spoof; it would invent a rule V8 happens to satisfy and then fail every Firefox, Tor Browser and LibreWolf user with a critical contradiction. The subset half stays unconditional, because it is engine-neutral and measured clean on every Gecko configuration. That second assertion is the interesting one, because it defeats the standard manoeuvre for hiding a global: `delete window.foo` followed by re-adding a convincing replacement. The replacement is appended, so it lands at the END of the property order, and the order itself becomes the evidence — no amount of making the VALUE look right can move it back to where the browser originally installed it. This is the largest single family in Kasada's deployed script: 44 of its 427 probes enumerate the global in both realms and sample length, five indices, and five slice indices from each. They can diff those samples against a server-side model of stock Chrome; this check has no baseline, so it asserts only what one realm can prove about the other. Integer-like keys are filtered first — those are the indexed frame accessors, and a page with subframes legitimately has more of them than a bare iframe.

How to resolve it

Do not delete or reassign globals to hide them — a fresh realm is built from the same blueprint as this one, so an absence here is visible against it, and re-adding a global puts it at the end of the property order where it never belonged. If a value must differ, change it at the browser layer, below JavaScript, so both realms derive it from one source rather than one realm being edited after the fact.

How automation gets caught, layer by layer

Read in the wild by

PerimeterX / HUMAN

Reads the globals HTMLPopupElement and NativeIOFile — two flag-gated experimental Chromium interfaces — off a hidden display:none iframe's contentWindow rather than the page's own window, flagging each in the payload if present. The same script reads showModalDialog off the page window, so the realm is chosen per probe rather than being a script-wide default.

Deployed PX collector, stample/ifood/source/main.min.js: `xI(){…t.a=xn("UGZYCbchcRyrzrag"),t[2]=xn("AngvirVBSvyr"),nG[t.a]&&(t[0]["FmYjbFMGJ14="]=!0),nG[t[2]]&&(t[0]["JVEQW2AxFGg="]=!0)}` — xn() is ROT13, so the names decode to 'HTMLPopupElement' and 'NativeIOFile'. nG is the hidden iframe's realm, from `nK(){(nH=hT.createElement("iframe")).style.display="none",…,nG=nH.contentWindow}` (hQ(166)="contentWindow"; `var nG` has no initializer), versus `hS=window` for the page's own — which xB() uses for its showModalDialog probe. ROT13 confirmed against observable output: xn("fubjZbqnyQvnybt")='showModalDialog', whose result rides hQ(390)="VQEgCxBhKjo=", and sample/1/decoded_payload_2.json shows `"VQEgCxBhKjo=": {"smd":{"ok":true,"ex":false}}`.

CreepJS

CreepJS, an open-source research demo rather than a production detector, enumerates the own property names of a hidden iframe's global instead of the page's, and separately flags window.chrome turning up among the last 50 keys of window — the position a re-added global lands in. It reads a single realm rather than diffing two; the cross-realm comparison is ours.

src/window/index.ts: `const win = PHANTOM_DARKNESS || window` / `let keys = Object.getOwnPropertyNames(win)`, plus the Gecko fixup `// if Firefox, remove the 'Event' key and push to end for consistent order` with `const firefoxKeyMovedByInspect = 'Event'`. PHANTOM_DARKNESS is the hidden iframe's contentWindow — src/lies/index.ts: `const { iframeWindow: PHANTOM_DARKNESS, div: PARENT_PHANTOM } = getPhantomIframe() || {}` (GHOST style: visibility:hidden, left:-10000px, appended via document.body.appendChild). src/headless/index.ts: `hasHighChromeIndex: (() => { const key = 'chrome'; const highIndexRange = -50; return (Object.keys(window).slice(highIndexRange).includes(key) && Object.getOwnPropertyNames(window).slice(highIndexRange).includes(key)) })()`

Kasada

Its single largest probe family: 44 of 427 probes enumerate the global object in BOTH the page and a fresh iframe, sampling the length plus five indices and five slice indices from each, then diffing the samples server-side.

win_own_props_idx0..4 / win_own_props_length / win_keys_idx0..4 / win_keys_length + the iframe_* twins

Kasada ips.js teardown — the full 427-probe list

Every attribution traces to a published artifact. See the sources and their limits.

Nearby checks in Native function integrity

See all 13 checks in Native function integrity
Who builds this test

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 window-globals-vs-realm belongs to.