Detection catalog
Every check Kitsune runs, grouped by signal layer. Convicting rules (coherence · automation · artifact) can label a session a bot; the rest corroborate.
143checks
97convicting
5layers
cross-layer 14
net.accept_encoding_vs_ua convictsUA claims a modern browser but Accept-Encoding omits Brotli (scripted client)net.accept_lang_vs_navigator convictsHTTP Accept-Language contradicts the JS navigator.languages localenet.ch_platform_header_vs_ua convictsHTTP Sec-CH-UA-Platform contradicts the JS UA platformnet.ch_ua_mobile_vs_ua convictsSec-CH-UA-Mobile form factor contradicts the UA's mobile-nessnet.ch_ua_version_vs_ua convictsSec-CH-UA brand version disagrees with the UA-string Chrome versionnet.ch_ua_vs_ua_browser convictsHTTP Sec-CH-UA brand contradicts the JS UA browsernet.datacenter_origin_proxied convictsWebRTC reveals a datacenter machine hidden behind a non-datacenter connectionnet.h2_vs_ua_browser convictsHTTP/2 (Akamai) fingerprint contradicts User-Agent browsernet.no_js_execution convictsPage request with a TLS fingerprint but no browser layer (no JS ran — scripted client)net.sec_fetch_vs_ua convictsUA claims a modern browser but the request omits Sec-Fetch metadata headersnet.tls_grease_vs_ua convictsUA claims a GREASEing-engine browser (Chromium/Safari) but the TLS ClientHello has no GREASEnet.tls_pq_keyshare_vs_ua convictsUA claims current Chrome but the TLS handshake offers no post-quantum key sharenet.tls_vs_ua_browser convictsJA4 browser family contradicts User-Agent browsernet.webrtc_ip_vs_observed WebRTC-revealed public IP contradicts the observed connection IP (proxied bot)network 20
net.ch_ua_no_grease_brand convictsChromium Sec-CH-UA brand list omits the GREASE brand (hardcoded header)net.fake_declared_crawler convictsA UA declaring a known crawler (Googlebot/Bingbot/…) whose IP fails forward-confirmed reverse DNSnet.h2_continuation_flood convictsHTTP/2 CONTINUATION flood (CVE-2024-27316) on this connectionnet.h2_control_flood convictsHTTP/2 control-frame flood (SETTINGS/PING — CVE-2019-9515/9512)net.h2_header_order_vs_ua convictsChromium UA but the HTTP/2 regular-header order is not chromium-shaped (JA4H)net.h2_madeyoureset convictsHTTP/2 MadeYouReset stream-reset coercion (CVE-2025-8671) on this connectionnet.h2_rapid_reset convictsHTTP/2 rapid-reset flood (CVE-2023-44487) on this connectionnet.h2_settings_vs_order convictsHTTP/2 SETTINGS-profile engine contradicts the pseudo-header-order enginenet.h2_unknown_vs_ua convictsModern-browser UA but the HTTP/2 stack matches no known browser enginenet.h2_unstable_within_session convictsHTTP/2 fingerprint (SETTINGS preface) changed within one sessionnet.h2_vs_tls_browser convictsHTTP/2 fingerprint browser contradicts the TLS (JA4) browsernet.ip_rotation_within_session convictsOne session egressed from many distinct IPs (rotating proxy pool)net.ja4_tool_vs_ua convictsJA4 is a non-browser HTTP client but the User-Agent claims a browsernet.ja4_unstable_within_session convictsTLS engine (JA4_b cipher identity) changed within one sessionnet.tcp_os_vs_ua convictsTCP/IP-stack OS kernel contradicts the OS the User-Agent claimsnet.tls_ext_order_static_within_session convictsChromium-JA4 session repeated one TLS extension order (no per-connection permutation)net.tls_os_vs_tcp_os convictsJA4-implied OS contradicts TCP/IP-implied OSnet.ua_rotation_within_session convictsOne session sent multiple distinct User-Agent strings (mid-session UA rotation)net.web_bot_auth_invalid convictsA request presents a Web Bot Auth (RFC 9421) signature that fails Ed25519 verificationnet.web_bot_auth_nonce_replay convictsA valid Web Bot Auth (RFC 9421) signature reuses an in-window nonce — a captured-credential replaybrowser 90
br.apple_ua_nonwebkit convictsA UA claiming Apple WebKit (Safari / any iOS browser) exposes a Blink-only structural APIbr.audio_noise convictsAudioContext fingerprint differs across identical renders (per-render perturbation)br.automation_globals convictsAutomation-framework global or webdriver DOM attribute presentbr.brave_spoofed convictsnavigator.brave is present but faked (isBrave is not a native function)br.canvas_geometry_noise convictsCanvas path geometry is non-deterministic (isPointInPath farbling, e.g. JShelter)br.canvas_lie convictsCanvas/WebGL API tampering detected (getter override)br.canvas_noise convictsSolid-fill canvas reads back perturbed (engine-level farbling, e.g. Brave)br.canvas_worker_vs_main convictsCanvas pixel hash differs between the main thread and a Worker OffscreenCanvasbr.cdc_artifacts convictsSelenium / chromedriver automation artifacts in window/documentbr.cdp_runtime_enabled convictsCDP Runtime.enable detected (prototype-chain Proxy ownKeys trap)br.ch_he_headless convictsUA-Client-Hints high-entropy brand list reveals HeadlessChromebr.ch_he_version_vs_ua convictsUA-CH high-entropy Chrome version contradicts the UA-string versionbr.coalesced_untrusted convictsA coalesced pointer batch contains an untrusted (constructor-built) event — fabricated coalescingbr.csp_bypassed convictsPage CSP not enforced (setBypassCSP — an automation context, never a real browser)br.domrect_invariant convictsgetBoundingClientRect is non-deterministic or disagrees with getClientRects — geometry shimbr.electron_process convictsRenderer exposes a Node process object — Electron / automation runtimebr.engine_feature_vs_ua convictsJS engine lacks an API its claimed Chrome version shipped — stale templatebr.engine_stack_vs_ua convictsJS-engine stack API (Error.stackTraceLimit = V8) contradicts the UA enginebr.error_engine_vs_ua convictsJS-engine error-message format contradicts the UA enginebr.fingerprint_unstable_within_session convictsOne session presented divergent hardware-invariant browser fingerprints (re-randomising anti-detect browser)br.firefox_ua_nongecko convictsA UA claiming Firefox lacks navigator.buildID — a Gecko-only surface, so it is not Geckobr.font_mac_internal convictsmacOS internal dot-prefixed system fonts are web-measurable (never on a real Mac)br.font_os_vs_ua convictsInstalled fonts imply an OS that contradicts the UA platformbr.headless_ua convictsUser-Agent advertises a headless browserbr.honeypot_interaction convictsInteracted with a honeypot bait element a human cannot reach (off-screen + aria-hidden + tabindex -1)br.iframe_divergence convictsnavigator differs between the main document and an iframebr.language_vs_languages convictsnavigator.language disagrees with navigator.languages[0] (spec-invariant violation)br.languages_worker_vs_main convictsnavigator.languages differs between the main thread and a Web Workerbr.measuretext_offscreen_vs convictsCanvas measureText differs between main and OffscreenCanvas — main-thread font hookbr.mobile_no_touch convictsPhone/tablet UA reports no touch capability (maxTouchPoints 0)br.native_invariant_violated convictsA built-in method claims native but violates native-function invariantsbr.nav_property_spoofed convictsA prototype-inherited navigator property (pdfViewerEnabled/mimeTypes) is an own propertybr.navplatform_vs_ua convictsnavigator.platform implies an OS that contradicts the UA platformbr.no_chrome_object convictsChrome User-Agent but window.chrome is absentbr.notification_getter_tampered convictsNotification.permission getter is non-native (faked to beat the notification floor)br.oscpu_vs_ua convictsnavigator.oscpu implies an OS that contradicts the UA platformbr.permissions_anomaly convictsNotification.permission contradicts the Permissions API statebr.plugins_spoofed convictsnavigator.plugins is an own property (patched via defineProperty)br.pointer_touch_incoherent convictsCSS coarse-pointer and navigator.maxTouchPoints disagree on touchbr.productsub_vs_ua convictsnavigator.productSub render engine contradicts the UAbr.readback_noise convictsAudioBuffer getChannelData and copyFromChannel disagree — readback noise shimbr.safari_ua_no_webkit_api convictsA UA claiming Safari lacks window.GestureEvent — a WebKit-only surface, so it is not WebKitbr.screen_impossible convictsAvailable screen area exceeds the physical screen (impossible geometry)br.timezone_inconsistent convictsIANA timeZone and getTimezoneOffset() disagree (a real browser derives both from the OS)br.timezone_offset_vs_intl convictsgetTimezoneOffset disagrees with the Intl IANA timezone's actual offsetbr.timezone_worker_vs_main convictsTimezone differs between the main thread and a Web Workerbr.tostring_tampered convictsA native function's toString no longer reads [native code]br.ua_platform_vs_ch_platform convictsnavigator/UA platform contradicts Sec-CH-UA-Platformbr.vendor_vs_ua convictsnavigator.vendor implies an engine that contradicts the UAbr.voice_os_vs_ua convictsInstalled TTS voices imply an OS that contradicts the UA platformbr.webdriver_getter_tampered convictsNavigator.prototype.webdriver getter is non-native (prototype patch)br.webdriver_present convictsnavigator.webdriver is truebr.webdriver_spoofed convictsnavigator.webdriver is an own property (patched via defineProperty)br.webgl_caps_worker_vs_main convictsWebGL capability vector (limits + extensions) differs between the main thread and a Worker OffscreenCanvasbr.webgl_getparameter_tampered convictsWebGLRenderingContext.getParameter is overridden (non-native toString)br.webgl_os_vs_ua convictsWebGL renderer implies an OS that contradicts the UA platformbr.webgl_renderer_artifact convictsWebGL renderer string is an anti-detect spoofing placeholder, not a real driverbr.webgl_renderer_caps_mismatch convictsWebGL renderer names a high-end GPU but the hardware capabilities are below its floor (spoofed string)br.webgl_worker_vs_main convictsWebGL GPU renderer differs between the main thread and a Worker OffscreenCanvasbr.webgpu_vendor_vs_webgl convictsWebGPU adapter GPU family contradicts the WebGL renderer (spoofed renderer on real hardware)br.worker_constructor_tampered convictsWeb Worker / OffscreenCanvas constructor is not native (worker-realm spoof injection)br.worker_divergence convictsnavigator differs between the main thread and a Web Workerbr.worker_source_rewritten convictsWeb Worker ran from a different source than the page passed (worker-scope spoof injection)br.adblock_present A content blocker hides the ad bait element (Camoufox default-bundles uBlock Origin)br.audio_missing No OfflineAudioContext (audio stack absent)br.codec_os_incoherent Non-Linux UA cannot play H.264/AAC (proprietary codecs a real Windows/macOS has via OS)br.color_depth_anomaly screen.colorDepth is not a real-display value (24/30/32)br.devicepixelratio_anomaly window.devicePixelRatio is not a positive finite numberbr.fingerprint_improbable Fingerprint joint (platform/gpu/screen/colour/cores) is improbable under the real-traffic priorbr.font_linux_leak Linux metric-compatible fonts (Arimo/Cousine/Tinos) present under a non-Linux UAbr.hover_none_desktop Non-mobile UA reports no hover capability (CSS hover:none)br.languages_empty navigator.languages is emptybr.low_hardware_concurrency navigator.hardwareConcurrency implausibly lowbr.macos_dpr1 macOS UA but devicePixelRatio is 1.0 (a modern Mac is Retina, dPR 2)br.media_devices_empty navigator.mediaDevices.enumerateDevices() is empty (no audio/video hardware)br.mimetypes_empty navigator.mimeTypes is emptybr.no_connection Chromium UA but navigator.connection is absentbr.no_devicememory Chromium UA but navigator.deviceMemory is undefinedbr.no_pdfviewer Chromium UA but pdfViewerEnabled is falsebr.no_plugins Desktop browser reports zero pluginsbr.platform_empty navigator.platform is emptybr.rfp_browser resistFingerprinting signature (UTC + letterboxed window + 2-core, all at once)br.screen_avail_invalid screen.availWidth/Height exceeds the physical screen sizebr.screen_zero Screen or outer window dimensions are zerobr.voices_empty No speech-synthesis voices (headless/container — a real desktop has OS TTS)br.webgl2_missing WebGL2 unsupported (headless software rendering)br.webgl_not_angle Chromium UA but the WebGL renderer is not ANGLE-wrapped — renderer spoofbr.webgl_software WebGL renderer is software (SwiftShader / llvmpipe / Mesa) — headless tellbr.webgpu_webgl_vs WebGL renderer claims a hardware GPU but WebGPU exposes no real adapter (spoofed renderer)br.webrtc_unavailable WebRTC gathers no ICE candidates (disabled/blocked)behavioral 15
bh.trace_replay_within_session convictsOne session replayed an identical pointer trajectory across page loads (record-and-replay bot)bh.action_cadence_deliberative Metronomic inter-action cadence at LLM-inference latencybh.click_without_trajectory Trusted mouse click with no pointer trajectory in the session (teleport-click)bh.input_entropy_floor Mouse-movement entropy below the human floorbh.input_via_paste Form value injected with no keystroke or trusted paste (programmatic input)bh.keystroke_entropy_floor Keystroke timing entropy below the human floorbh.keystroke_interval_floor Median inter-keystroke interval below the human cadence floorbh.mobile_keystroke_interval_floor Mobile session typing faster than any human thumb cadencebh.no_input_before_action Action (submit/nav) with zero pointer eventsbh.path_too_straight Mouse path is unnaturally straight (start->end ~= total length)bh.power_law_violation Mouse motion violates the 2/3 power law (speed independent of curvature — synthetic path)bh.scroll_teleport Programmatic scroll jump with no wheel/scroll-key inputbh.synthetic_no_coalesced Long pointer stream never coalesces (CDP-injected input, not hardware)bh.touch_uniform_velocity Touch-swipe velocity too uniform for a human finger (mobile)bh.uniform_velocity Mouse moves at near-constant speed (low velocity CV)reputation 4
rep.abuse_listed Source IP is on an abuse/threat reputation listrep.datacenter_asn Source IP belongs to a datacenter / hosting ASNrep.known_proxy_exit Source IP is a known VPN / proxy / Tor exitrep.webrtc_origin_datacenter WebRTC-leaked real origin IP belongs to a datacenter / hosting ASN