Skip to content

HackingLZ/fingerprint_js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 

Repository files navigation

VexTrio Browser Fingerprint Analyzer

An interactive browser-based tool for running and analyzing browser fingerprinting and automation/bot detection checks. Built on top of the VexTrio fingerprinting script documented in the original research below, extended with modern detection techniques from 2022–2025.

Original Research

All checks in the a-series (a1–a92) are derived from the VexTrio threat actor's fingerprinting script, originally documented by gi7w0rm:

gi7w0rmVexTrio's Browser Fingerprinting https://gi7w0rm.medium.com/vextrios-browser-fingerprinting-aeb721be6e30

VexTrio is a large-scale traffic distribution system (TDS) used to monetize stolen traffic by routing victims to scam, phishing, and malware pages. Their fingerprinting script ran silently on compromised sites to determine whether a visitor was a real human or a security researcher/bot before redirecting.


How It Works

Open Fingerprint.html in a browser. Click Run All Checks. Each check runs synchronously against the current browser environment and returns one of:

Result Meaning
aNN:0 / bNN:0 PASS — no anomaly detected
aNN:1 / bNN:1 FAIL — browser flagged as suspicious/automated
aNN:e / bNN:e ERROR — check threw an exception

The verdict a0:1 means the browser was flagged as suspicious by at least one check.

The Code Generator panel lets you export any subset of checks as a deployable JavaScript snippet in three styles (chained if-else, loop, standalone result map).


Checks Reference

a-series: Original VexTrio Checks

ID Name Detection Method
a1 Language ISO Code Mismatch navigator.languages[0] ISO vs navigator.language ISO
a2 Window vs Screen Size screen.width/height vs screen.availWidth/Height
a3 OSCPU vs UserAgent OS navigator.oscpu (Firefox-only) vs UA OS string
a4 OSCPU on Non-Firefox navigator.oscpu defined on non-Firefox = spoofed
a5 Platform vs UserAgent navigator.platform cross-referenced with UA OS
a6 Plugins Undefined on Non-Windows navigator.plugins undefined on non-Windows
a7 Browser Build Number navigator.productSub must be "20030107" for Chrome/Safari
a8 eval.toString() Length eval.toString().length varies: 33=Chromium, 39=IE, 37=Safari iOS
a9 toSource() Function Obsolete Mozilla method only in old Firefox
a10 WebGL Vendor vs OS/Browser UNMASKED_VENDOR_WEBGL cross-checked against UA OS and browser type
a11 WebDriver Detection navigator.webdriver === true
a12 Permission State Anomaly Notification.permission === "denied" + state === "prompt"
a13 Permissions API Integrity navigator.permissions.query.toString() must be native code
a14 DevTools Console Detection Chrome: regex .toString() call count in console.debug()
a15 PhantomJS Detection callPhantom, _phantom, phantom in window
a16 Browser Automation DOM Selenium/WebDriver/Nightmare/PhantomJS DOM properties
a17 Phantomas Detection __phantomas in window
a18 Selenium DOM Cache $[a-z]dc_ pattern with .cache_ in document properties
a19 Node.js Buffer window.Buffer !== undefined
a20 Chromium Automation Driver window.domAutomation / window.domAutomationController
a21 setTimeout Integrity setTimeout.toString() must match native code
a22 setInterval Integrity setInterval.toString() must match native code
a42 XHR Open Integrity XMLHttpRequest.prototype.open.toString() — checks for klIsCORSRequest
a43 XHR Send Integrity XMLHttpRequest.prototype.send.toString() — same
a60 HeadlessChrome UA String UA contains phantomjs, headless, avira, googleweblight
a78 Stack Trace Behavior Stack trace matches Puppeteer-stealth Object.apply(<anonymous>) regex
a86 iOS Logical Processors iOS UA with hardwareConcurrency > 4 (Safari dropped API support)
a89 Browser Voice List "Lekha" voice (Apple-only) present on Windows/Android/Linux
a92 VirtualBox WebGL WebGL renderer contains "VirtualBox"

b-series: Extended Checks (2022–2025)

These checks were added based on modern research into headless browser detection, stealth evasion bypass analysis, and browser inconsistency research.

ID Name Detection Method Source / Technique
b1 window.chrome Object Integrity Chrome UA must have window.chrome.loadTimes / csi / runtime / app; automation often exposes empty {} Puppeteer-stealth chrome.runtime evasion; Antoine Vastel's headless Chrome research
b2 ChromeDriver cdc_ Property Injection ChromeDriver injects window.$cdc_adoQpoasnfa76pfcZLmcfl_* properties detectable via Object.getOwnPropertyNames ChromeDriver source; Berstend/puppeteer-extra stealth evasions
b3 UA-CH Platform vs UserAgent navigator.userAgentData.platform must match OS from UA string; also mobile flag must match UA-CH (User-Agent Client Hints) inconsistency research; FingerprintJS Pro signals
b4 Intl Timezone vs Date Offset Intl.DateTimeFormat().resolvedOptions().timeZone computed offset must agree with Date.getTimezoneOffset() within 90 min Timezone spoofing detection; BrowserLeaks.com, CreepJS
b5 navigator.vendor vs Browser Chrome="Google Inc.", Safari="Apple Computer, Inc.", Firefox="" Well-known UA inconsistency; FingerprintJS
b6 iOS devicePixelRatio All iOS devices since iPhone 4 (2010) have devicePixelRatio >= 2 (Retina) Hardware consistency check; nstbrowser/anti-detect research
b7 Touch Points on Mobile OS iOS/Android UA must have navigator.maxTouchPoints > 0 BrowserLeaks touch detection; headless browser emulation checks
b8 Error.stackTraceLimit V8/Chrome-only property; present in Chrome/Edge, absent in Firefox/Safari V8 engine fingerprinting; CreepJS engine checks
b9 Prototype Lie Detection Checks Function.prototype.toString.call(toString) is native; detects Proxy wrappers on navigator.webdriver, plugins, languages, userAgent getters CreepJS queryLies() technique; puppeteer-extra-plugin-stealth evasion analysis
b10 Canvas Rendering Integrity canvas.toDataURL() must produce non-empty output (>200 bytes); "data:," = canvas blocked Headless canvas stripping detection; FingerprintJS canvas check
b11 AudioContext Sample Rate AudioContext.sampleRate must be a standard rate (44100/48000/etc.); abnormal = synthetic env AudioContext fingerprinting; CreepJS audio fingerprint
b12 Network Information API Chrome on Android must expose navigator.connection (NetworkInformation API) Chrome Android API surface check
b13 Playwright Window Artifacts Checks for __playwright, __pw_manual, __pw_preview, __pwInitScripts in window Playwright source code inspection; playwright-stealth bypass research
b14 Notification API Presence Desktop Chrome/Firefox/Edge must have Notification constructor; absent = stripped automation env API surface completeness check; headless stripping research
b15 Math IEEE 754 Consistency Math.tan(-1e308), Math.acos(1.0001), Math.log(-1), 1/-0 must return standard IEEE 754 values VM/non-standard JS engine detection; CreepJS math fingerprint
b16 document.hasFocus() Headless Chrome returns false; real user sessions are focused Headless Chrome behavioral difference; Antoine Vastel 2023 research
b17 UA-CH Brands Decoy Entry Chromium's navigator.userAgentData.brands always includes a "Not_A Brand" / "Not;A Brand" decoy; absent = spoofed brands Chromium UA-CH spec implementation; anti-spoofing check
b18 Media Devices API Desktop Chrome/Firefox/Edge must expose navigator.mediaDevices.enumerateDevices API surface completeness; headless stripping
b19 Brave Browser Detection navigator.brave.isBrave() present while UA claims Chrome = Brave masquerading Brave browser fingerprinting; unmasked API exposure
b20 WebRTC Presence RTCPeerConnection must exist in modern Chrome/Firefox/Edge/Safari; absent = stripped env API surface completeness; headless/privacy proxy detection
b21 Outer Window Dimensions window.outerWidth/Height === 0 = old headless Chrome (pre-112) Headless behavioral difference; Chrome 112 headless unification
b22 Connection RTT Zero navigator.connection.rtt === 0 = headless; real browsers report non-zero RTT Network Information API headless signal; infosimples/detect-headless
b23 PDF Viewer Enabled Chrome 105+ must have pdfViewerEnabled=true; false = stripped Chromium build MDN navigator.pdfViewerEnabled; headless stripping research
b24 MimeTypeArray Prototype Object.prototype.toString.call(navigator.mimeTypes) must be "[object MimeTypeArray]" Native prototype integrity check
b25 Image Constructor Integrity new Image() instanceof HTMLImageElement must be true DOM prototype integrity; headless API stripping
b26 Media Codec Chromium vs Chrome canPlayType('audio/mp4; codecs="mp4a.40.2"') returns "probably" on real Chrome, "maybe" on Chromium Licensed codec difference; privacycheck.sec.lrz.de; deviceandbrowserinfo.com
b27 Google TTS Voice Count Chrome UA with >10 voices but 0 starting with "Google " = open-source Chromium binary deviceandbrowserinfo.com headless Chrome fingerprint 2024
b28 deviceMemory Valid Set navigator.deviceMemory must be in {0.25, 0.5, 1, 2, 4, 8}; any other value = spoofed Castle.io deviceMemory bot detection deep dive
b29 iframe webdriver Leak Creates iframe and checks iframe.contentWindow.navigator.webdriver; stealth patches often miss iframes Berstend/puppeteer-extra-plugin-stealth iframe.contentWindow evasion
b30 UA-CH "Google Chrome" Brand Chrome UA must include "Google Chrome" in navigator.userAgentData.brands; Chromium builds lack this Chromium UA-CH spec; deviceandbrowserinfo.com 2024
b31 macOS screen.availTop macOS always reserves ≥25px for the menu bar (screen.availTop > 0); headless Chrome defaults to 0 Chromium headless screen_info README; Chromium headless/screen_info/README.md
b32 Network Downlink Zero navigator.connection.downlink === 0 = headless; real browsers report positive Mbps Network Information API; infosimples/detect-headless; WICG netinfo spec
b33 ChromeDriver webdriverAsyncExecutor window.__$webdriverAsyncExecutor presence; extended prototype-chain scan for cdc_*_Array/Promise/Symbol/Proxy/Object variants CreepJS issue #182; brotector.js; ultrafunkamsterdam/undetected-chromedriver
b34 chrome.loadTimes First Paint chrome.loadTimes().firstPaintAfterLoadTime === 0 in headless = no GPU render pipeline Chrome loadTimes deprecation docs; Castle.io headless Chrome research

Key Research & References

Original VexTrio Research

Headless Chrome Detection

Stealth Evasion (Reverse-Engineer for Detection)

Multi-Signal Fingerprinting

ChromeDriver & CDP Artifacts

UA-CH (User-Agent Client Hints)


Playwright Test Results

The tool was validated against Playwright headless Chromium across three scenarios. All new b-series checks were verified:

Tested against Playwright 1.58.2 + Chromium on macOS. Tool: 63 total checks.

Scenario 1: Default headless (no evasion)

PASS: 51 / 63  FAIL: 12
Flagged: a11 (webdriver=true), a12 (permission anomaly), a60 (HeadlessChrome UA),
         b1 (window.chrome missing), b11 (sampleRate=24000), b18 (no mediaDevices),
         b22 (rtt=0), b23 (pdfViewerEnabled=false), b27 (0 Google TTS voices),
         b28 (deviceMemory undefined), b29 (iframe webdriver leak), b31 (screen.availTop=0)

Scenario 2: --disable-blink-features=AutomationControlled

PASS: 53 / 63  FAIL: 10
Bypassed: a11 (webdriver), b29 (iframe leak). Still flagged: a12, a60, b1, b11, b18, b22, b23, b27, b28, b31

Scenario 3: Full UA spoof + viewport (common bot evasion)

PASS: 54 / 63  FAIL: 9
Bypassed: a11, a60, b29. Still flagged: a12, b1, b11, b18, b22, b23, b27, b28, b31

Key findings:

  • Even with full stealth UA spoofing, 9 checks still flag Playwright headless Chromium
  • The most persistent signals are Chromium-binary vs real Chrome differences: window.chrome missing (b1), AudioContext sampleRate=24000Hz (b11), no mediaDevices (b18), RTT=0 (b22), pdfViewerEnabled=false (b23), 0 Google TTS voices (b27), deviceMemory undefined (b28)
  • b31 fires in all scenarios: Playwright's headless Chromium on macOS reports screen.availTop=0 because there is no OS menu bar in the headless window session
  • Playwright headless Chrome returns AudioContext.sampleRate = 24000 (not in the standard 44100/48000 set used by real browsers)
  • b27 (0 Google TTS voices with 191 total) is highly reliable: Playwright uses the open-source Chromium binary which ships without Google's proprietary TTS engine
  • b26 (codec canPlayType check) does not fire on macOS — Playwright's bundled Chromium includes FFmpeg and returns "probably" for AAC/H.264; this check is more reliable on Linux CI environments
  • b32 (downlink=0), b33 (cdc_ async executor), b34 (loadTimes firstPaint) do not fire against Playwright: b32 because Playwright Chromium exposes a non-zero downlink value; b33 because __$webdriverAsyncExecutor is ChromeDriver-specific; b34 because window.chrome is absent in headless (b1 fires first)

Usage

  1. Open Fingerprint.html in a browser (no server required — static HTML)
  2. Click Run All Checks
  3. Review per-check results. Red = flagged, Green = clean, Yellow = error
  4. Use the Code Generator to export checks as embeddable JS

Generating a deployable script

The Code Generator supports three output styles:

  • Chained — short-circuit if/else if chain (matches original VexTrio style)
  • Loop — iterates an array of check functions
  • Standalone — returns {verdict, checks} map for full per-check logging

License

For research and educational purposes. Techniques documented here are used in the wild by threat actors and security vendors alike.

About

Browser fingerprinting and automation/bot detection analyzer — VexTrio a-series + extended b-series checks

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Languages