the machine delivers no more parallelism than it claims cores
Check id hardware-concurrency-vs-parallelism
What an ordinary browser yields
Parallel throughput at or below the claimed core count (severity: warn). Not scored on Brave, which farbles the count by default, or on WebKit engines, which clamp it.
What a detector infers
The plain hardwareConcurrency row can only ask whether the number looks sane, because no second API reports a core count. There is a second SOURCE though, and it is not an API at all: the hardware. Run identical CPU-bound work in more workers than the machine claims cores and the wall-clock speedup plateaus at however many cores really exist, because nothing can deliver more parallelism than it has. That makes the comparison one-sided, which is the whole reason it is safe to score. Measured throughput ABOVE the claim is impossible and therefore a contradiction; measured BELOW is completely ordinary, since background load, thermal limits, efficiency cores, a busy machine and a throttled tab all push it down. Every way this measurement can go wrong except one moves it toward the safe side. Measured on one sixteen-core machine with twenty-four workers against a best-of-two single-worker baseline: an untouched Gecko claiming sixteen reached 14.34x, Chromium claiming sixteen reached 11.97x, and a Gecko stealth build claiming eight reached 14.62x, 12.23x and 12.23x across three launches. The browsers that publish their true core count land at 0.75 to 0.90 of that claim and the spoof at 1.53 to 1.83 of its own, so for a browser REPORTING THE COUNT IT ACTUALLY HAS the threshold sits in a wide gap: it would need thirty per cent measurement error to reach 1.3. That is the only claim the gap supports, and it is worth being exact about, because the space above the threshold is not empty. Two stock browsers that under-report cores by default land inside it: Brave measured 12.37x against a claim of nine, a ratio of 1.37, and WebKit 11.27x against a claim of eight, a ratio of 1.41 — both above 1.3, both only about six per cent above it, and neither arriving there through measurement error. They arrive there by publishing fewer cores than the machine has, which is the same observable a spoof produces, so no threshold separates them and the two declines described below are what handles them instead. The safety argument was tested rather than asserted, because the single way this measurement can inflate is a slow single-worker baseline, and a busy machine is exactly when that might happen. An honest browser reporting its true core count was run three times against a machine saturated by sixteen external CPU burners and the row did not fire once: heavy load pushes the batch down as readily as the baseline, so the ratio does not climb. The audit took 11.1 seconds idle and 11.9 seconds under that saturation, which is what this costs. The other way a machine delivers less than it reports is a CPU quota, which is how most containers run, and that was tested too: a browser pinned to 8, then 4, then 2 of sixteen processors kept reporting sixteen and the row stayed quiet at every level, including the two-processor case where the claim exceeds what is usable eightfold. A restriction lowers the batch while the single-worker baseline still gets a whole processor, so a quota moves the ratio down rather than up. Seventeen control runs across a clean machine, a saturated one and three quota levels have produced no firing. It also fires in situ rather than only on a bench — four consecutive launches of a stealth build claiming eight cores measured 13.50x, 13.39x, 12.00x and 12.72x from inside the full audit, with every other check competing for the same CPU. Worth knowing what it cannot do, too. It only catches a count reported LOWER than the hardware, which is the direction stealth builds move it; a browser claiming more cores than it has is not contradicted by a machine that simply fails to deliver them, because that is what an ordinary loaded machine looks like too. The direction is deliberate and was measured: this check only ever fires when the machine delivers MORE parallelism than the browser claims cores, never less. On a real 16-core host reporting hardwareConcurrency 16, measured speedups were 3.83x at 4 workers, 6.23x at 8, 8.11x at 16, 10.61x at 24, then 10.27x at 32 and 10.22x at 48 - delivered parallelism SATURATES around 10.5x, well under the 16 claimed, because hyperthreading yields roughly 1.3x per logical pair rather than 2x and memory bandwidth caps the rest. So under-delivery is the normal case for an honest browser and proves nothing, while over-delivery is physically impossible to explain away: a machine cannot run 11 CPU-bound loops in parallel on 4 cores. That also means a browser OVER-claiming cores (Camoufox was measured reporting 32 on a 16-core box) is not detectable here, because it is indistinguishable from a loaded 32-core host - and inventing a threshold for that would fail on every genuinely busy machine. Two shipping browsers report fewer cores than they have without being asked to, and the row declines on both rather than calling a default install a spoof. Brave farbles hardwareConcurrency as a stock privacy feature while the scheduler underneath still uses every core: measured, a stock Brave reported 9 on the sixteen-core reference machine, so the workers over-delivered and the row fired on an untouched browser. WebKit does it by ceiling rather than by farbling — JavaScriptCore-based browsers clamp the number they publish instead of reporting the machine's real one, so above the cap it is an upper bound and not a measurement at all; measured, a stock WebKit reported 8 on the same machine. The WebKit exemption is keyed to the ENGINE rather than to a brand, because the clamp is the engine's and every WebKit browser inherits it, and it is deliberately not phrased as "anything that is not Blink": Gecko is also not Blink, publishes its true count, and stays fully scored, which is why bare Gecko sits at 0.90 of its claim above. Neither exemption is a blanket pass — both apply only to a run that would otherwise fire, so on a host at or below WebKit's cap the published count is the real one and the row still scores there. The Brave exemption also asks for more than the presence of navigator.brave, which is a forgeable own property and would otherwise let one page-world assignment silence a hardware-grounded row: the engine must measure as V8 through the RangeError oracle, and navigator.brave.isBrave must stringify as a genuine native function, both of which a real Brave satisfies and an assignment does not. The WebKit arm is deliberately broader than it could be, for a reason worth stating plainly rather than glossing. The clamp is the smaller of the real count and the cap, so below the cap the published number is the true one and a stealth JavaScriptCore build claiming less than its host would in principle be separable — the gate could then require the claim to sit at the cap. It does not, because WE CANNOT BOUND THE CAP: exactly one WebKit measurement of it exists here, a build publishing eight on the sixteen-core reference machine, which fixes the cap for that one build on that one port and says nothing about Safari on macOS or iOS or about the GTK and WPE ports. A cap invented from a single sample is how a threshold starts making false accusations, so the arm stays engine-wide. What that gives up is a stealth WebKit build lowering the count on a many-core host; the price of narrowing it on a guessed cap would be convicting stock Safari, which is the worse error.
How to resolve it
Lowering hardwareConcurrency does not slow the machine down. The core count is a claim and parallel throughput is a measurement, and the second one wins. A build reporting fewer cores than it has is contradicted by any page willing to spend a few hundred milliseconds in Workers. Report the real count, or genuinely restrict the parallelism so the claim becomes true.
Nearby checks in Navigator identity
- 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… - the Keyboard API's presence matches the claimed engine and form factor
keyboard-api-vs-platformThe Keyboard API — navigator.keyboard, with getLayoutMap and lock — ships in desktop Chromium and nowhere else: not in Gecko, not in WebKit… - browser-brand and context hints agree with a fresh realm
brand-hints-vs-realmSome of the cheapest signals to fake are the ones that say which browser this is: navigator.brave exists only in Brave, window.duckduckgo… - location.origin is the serialisation of its own protocol, host and port
location-origin-coherenceAn origin is not stored next to a URL, it is serialised from it: for an http or https document, origin is exactly the scheme, followed by… - navigator.vendor is the constant the measured engine compiles in
navigator-vendor-vs-enginenavigator.vendor is not a preference or a setting — it is a string constant compiled into the engine.
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 hardware-concurrency-vs-parallelism belongs to.