Skip to content
All fingerprint checksEngine & OS oracles

JavaScript and WebAssembly read the same CPU

Check id cpu-arch-nan-wasm-vs-js

What an ordinary browser yields

The JavaScript and WebAssembly readings of the quiet-NaN sign bit agreeing. N/A where WebAssembly is unavailable or refused (severity: warn).

What a detector infers

IEEE-754 leaves the sign bit and payload of a quiet NaN to the implementation, and the two dominant architectures chose differently: x86 sets the sign bit on the default quiet NaN (0xFFF8000000000000 for f64), ARM clears it (0x7FF8000000000000). Dividing a runtime zero by itself and reading that bit therefore names the processor. The row cpu-arch-nan-vs-uach already compares that reading against the architecture Client Hint - but it reads the bit with `new Uint32Array(new Float64Array([z/z]).buffer)[1]`, and every object in that expression belongs to the page world. MEASURED on this machine, on this page: redefining Float64Array so that it clears the sign bit of a NaN made that row read "arm" on genuine x86 hardware. It simply believed the override. That is a hole in a deployed check, demonstrated rather than supposed. WebAssembly closes it. The same division compiled to a machine instruction, with the result reinterpreted as an integer inside the module, never passes the bit through a JavaScript object a page could have replaced - measured, the same override that flipped the JavaScript reading to arm left the WebAssembly reading at x86. A 43-byte module is enough, hand-assembled because browsers ship no assembler: (func (export "s") (param f64) (result i32) local.get 0, local.get 0, f64.div, i64.reinterpret_f64, i64.const 63, i64.shr_u, i32.wrap_i64). The dividend is a PARAMETER, not a literal, for the same reason the older row uses Math.random()*0 - V8 constant-folds a literal 0/0 to the canonical NaN with the sign clear, which would make every x86 machine read as ARM. Nothing here is compared against a table of architectures: both readings are taken live on the machine running the audit, so the row asserts only that one processor gives one answer, and there is no constant in it to go stale. Technique: Scrapfly, which also documents relaxed-SIMD operations (f32x4.relaxed_min, i32x4.relaxed_trunc_f64x2) as a second architecture oracle - not implemented here, because relaxed SIMD is unevenly available and the NaN bit already answers the question.

How to resolve it

Stop rewriting the typed-array path used to read NaN bits. It is a surface a page can reach, so patching it produces exactly this contradiction - a machine whose two accounts of its own floating-point unit disagree, which is rarer and more legible than whichever architecture was being hidden. If a different architecture is genuinely required, run on that architecture.

Read in the wild by

Scrapfly

Documents the quiet-NaN sign bit as a CPU architecture oracle reachable from both JavaScript and a small WebAssembly module, and details what spoofing an ARM persona on x86 would require across V8's compiler tiers.

x86 f64 quiet NaN 0xFFF8000000000000 vs ARM 0x7FF8000000000000; f32 0xFFC00000 vs 0x7FC00000

How WebAssembly leaks your CPU architecture

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

Other checks in Engine & OS oracles

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 Engine & OS oracles 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 Engine & OS oracles — the family cpu-arch-nan-wasm-vs-js belongs to.