Detection catalog
Every check Kitsune runs, by layer. A convicting check — a cross-layer contradiction, an automation artifact, a forged native — can call a session a bot on its own. The rest only add weight.
200checks
153convicting
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 25
net.ch_ua_mobile_no_model convictsMobile Sec-CH-UA-Mobile ?1 but Sec-CH-UA-Model is empty — desktop faking Androidnet.ch_ua_no_grease_brand convictsChromium Sec-CH-UA brand list omits the GREASE brand (hardcoded header)net.ch_ua_on_non_chromium_ua convictsNon-Chromium UA (Safari/Firefox) sends Sec-CH-UA (a Blink-only header) — Chromium faking itnet.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.slow_http_attack convictsHTTP/1.1 slow-header (slowloris) connection holdnet.tcp_os_vs_ua convictsTCP/IP-stack OS kernel contradicts the OS the User-Agent claimsnet.tcp_static_window convictsTCP receive window never auto-tuned across the flow (non-kernel stack)net.tcp_syn_anomaly convictsTCP SYN option VALUES contradict the OS its option order classifies asnet.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 119
br.android_mobile_dpr1 convictsAndroid Mobile UA with devicePixelRatio 1 — a phone is never 1xbr.android_model_dpr_incoherent convictsAndroid Pixel model paired with the wrong device-fixed devicePixelRatiobr.android_model_gpu_incoherent convictsAndroid model paired with a mobile GPU family that model never shippedbr.android_model_os_exceeds convictsEOL Android Pixel model paired with an OS version newer than its last updatebr.android_model_os_predates convictsAndroid Pixel model paired with an OS version older than the device shipped withbr.android_model_screen_incoherent convictsAndroid device model does not match its device-fixed screen geometrybr.android_no_contacts_api convictsAndroid Chrome Mobile UA lacking navigator.contacts (a mobile-only web API)br.android_phone_screen_oversized convictsAndroid phone UA reports a screen larger than any real Android phonebr.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.battery_api_vs_gecko_ua convictsFirefox/Gecko UA that still exposes the Chromium-only Battery API (navigator.getBattery)br.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.devicememory_vs_engine convictsFirefox/Safari UA but navigator.deviceMemory (a Blink-only API) is presentbr.devicememory_worker_divergence convictsnavigator.deviceMemory differs between the main thread and a Workerbr.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.gpu_uniform_underreport convictsWebGL vertex-uniform limit reported below what the GL compiler actually enforcesbr.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.ios_dpr_incoherent convictsiOS UA reports a devicePixelRatio no real iPhone/iPad uses (not 2 or 3)br.ios_no_standalone convictsiOS UA lacks navigator.standalone (iOS-Safari-only surface) — not genuine iOS Safaribr.ios_screen_desktop_res convictsiOS UA reports a common desktop screen resolution (no iPhone/iPad ships one)br.ios_screen_offmanifold convictsiOS UA reports a screen matching no real iPhone/iPad geometry (full device set)br.ios_screen_oversized convictsiOS UA reports a screen larger than any real iPhone/iPadbr.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_cores_high convictsMobile UA exposes more than 8 CPU cores — a phone SoC does notbr.mobile_gpu_caps_mismatch convictsHigh-end mobile GPU string but MAX_TEXTURE_SIZE below the 16384 mobile floorbr.mobile_gpu_not_mobile convictsMobile UA renders WebGL on a non-mobile GPU (desktop/software renderer)br.mobile_gpu_uniforms_software convictsMobile GPU string with software/desktop-level vertex or fragment uniform capacitybr.mobile_no_js_model convictsMobile userAgentData but getHighEntropyValues().model is empty — desktop faking Android (JS surface)br.mobile_no_touch convictsPhone/tablet UA reports no touch capability (maxTouchPoints 0)br.mobile_pointer_hover_desktop convictsMobile UA but the primary pointer is fine / a hovering pointer exists (desktop pointer surface)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_depth_incoherent convictsscreen.pixelDepth and screen.colorDepth disagree (aliases that are always equal on a real display)br.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.uadata_model_worker_divergence convictsgetHighEntropyValues().model differs between the main thread and a Workerbr.uadata_worker_divergence convictsnavigator.userAgentData differs between the main thread and a Workerbr.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_maxtexture_unallocatable convictsWebGL MAX_TEXTURE_SIZE claimed but a texture of that dimension cannot be allocatedbr.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_removed convictswindow.Worker absent while the collector runs — the Worker realm was stripped to hide from divergence guardsbr.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_perf_vs_renderer WebGL renderer names hardware but renders at software speed — the substance behind the stringbr.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 38
bh.arena_audio_superhuman convictsAudio CAPTCHA answered correctly faster than its clip plays — ASR automation, not a listenerbh.arena_captcha_superhuman convictsCAPTCHA answered correctly faster than a human can read and respond — automated solverbh.arena_count_superhuman convictsCounting gate answered correctly faster than a human can scan the scenebh.arena_hold_robotic convictsPress-and-hold gate solved with a static (no-tremor) hold or an impossible claimed hold timebh.arena_honeypot_filled convictsFilled a hidden honeypot form field — a naive form-filling bot, never a humanbh.arena_keymap_no_exploration convictsRemapped-keyboard target typed correctly with zero exploration — the mapping was decoded, not discoveredbh.arena_localize_superhuman convictsPoint-localization gate solved with a pixel-perfect centroid click or impossibly fastbh.arena_match_superhuman convictsOrientation-match gate solved faster than a human can scan a reference plus N candidatesbh.arena_pattern_superhuman convictsTrace-the-pattern stroke hugs the ideal path too closely (no hand tremor) or is impossibly fastbh.arena_pursuit_superhuman convictsSmooth-pursuit tracking held within a few px of the moving target (superhuman tracking accuracy)bh.arena_queue_bypass convictsTook a virtual-queue protected action BEFORE admission — skipped the wait, a queue-bypass botbh.arena_queue_hoarding convictsOne session holding many concurrent virtual-queue positions — a position-hoarding scalperbh.arena_queue_superhuman convictsActed on a virtual-queue admission faster than a human can perceive it — position-holding botbh.arena_reaction_superhuman convictsReaction-time gate answered faster than the human physiological floor (or before the go cue)bh.arena_seqclick_superhuman convictsOrdered click-in-sequence gate solved faster than human target-location or at a metronomic cadencebh.arena_shell_precomputed convictsShell-game answered correctly before the shuffle could finish — swap payload precomputed, not watchedbh.arena_slide_superhuman convictsSliding-tile puzzle solved with an optimal (minimum-move) plan or impossibly fastbh.arena_spotdiff_superhuman convictsSpot-the-difference solved with pixel-perfect diff clicks (image-diff) or superhuman scan speedbh.arena_stale_snapshot convictsActed on a moving target's SECONDS-OLD position — a snapshot-then-slowly-reason LLM agentbh.arena_timing_superhuman convictsMotor-timing gate solved with superhuman release precision or impossible claimed hold timebh.arena_trajectory_forged convictsSlider/rotate drag trajectory claims more drag-time than the whole server-observed solve — synthesizedbh.session_flow_robotic convictsMulti-step gate flow paced at machine-regular intervals (near-zero inter-step CV — a timer, not a human)bh.session_flow_superhuman convictsMulti-step gate flow completed at superhuman inter-step cadence (session-intent, not a single step)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