A UA claiming Firefox lacks navigator.buildID — a Gecko-only surface, so it is not Gecko
br.firefox_ua_nongecko · convicts
What it catches
The Gecko analog of apple_ua_nonwebkit. navigator.buildID is a Gecko-ONLY surface: every real Firefox — and every Gecko browser (Tor, Mullvad, LibreWolf, ESR, Nightly) — exposes it as a present non-empty string (release builds freeze it to '20181001000000' for anti-fingerprinting, but it is always present). Blink (Chromium) and WebKit (Safari) have NO navigator.buildID at all. GROUNDED on the real-browser second source: a live Playwright Firefox reports buildID='20181001000000' (string) while a live Chromium reports it undefined. So a UA claiming Firefox (uaEngine 'firefox', the collector's own UA classification) with buildID absent/empty is a non-Gecko engine (Chromium/WebKit) faking a Firefox UA — the collector fires firefox_ua_nongecko only in that case. STRUCTURAL positive-surface tell, complementary to engine_stack_vs_ua (the captureStackTrace channel): a spoof that DELETES Error.captureStackTrace to beat engine_stack still cannot synthesise a real Gecko buildID surface. FP-safe: every real Gecko browser has buildID present → never fires on a real Firefox; a real Chrome/Safari has uaEngine chromium/safari so the rule is gated off (unknown never fires). Live positive: the spoof-ua evader (Playwright Chromium under a Firefox UA) trips it. Browserforge calibration does not emit buildID, so it cannot raise the legit flag rate.
Signals it reads
browser.firefox_ua_nongecko
How it fires
present
Evaders it caught 1
Bypassed by 10
Frontier evaders that reach the detector uncaught (scored only suspicious, defeating every convicting tell) — this check is not one that stops them. The red-team frontier this detection still has to convict.