Creepy device and browser fingerprinting
MIT License
https://abrahamjuliot.github.io/creepjs
The purpose of this project is to shed light on weaknesses and privacy leaks among modern anti-fingerprinting extensions and browsers.
Tests are focused on:
Service is limited to the CreepJS GitHub page.
Prediction API: https://creepjs-api.web.app/decrypt
/decrypt
captures fingerprints (Canvas, WebGL, etc.) in a data model and renders the data to cloud storage. The data model follows a set of instructions on how to respond if the fingerprint appears again. This includes reject, merge, timestamp, modify, log data, and self-learn from patterns. Some patterns are configured to trigger a manual review.
Newly discovered data starts off with a low score. If the data reappears with unique visits, the score will improve. If the score does not improve within 3 days, the data will be placed in a queue for auto-deletion. Any data with a last visit timestamp older than 7 days is automatically deleted. This design aims to make it difficult for abnormal data to blend in and establish any level of trust over time.
Fingerprint API: https://creepjs-api.web.app/fp
/fp
computes a fingerprint profile derived from unique patterns. If certain suspicious patterns are detected, then the Prediction API will go into "locked" mode, in which case all further learning and data merging on the server will be shut down.
Web Traffic API: https://creepjs-api.web.app/analysis
/analysis
creates a hidden fingerprint profile and collects as much unique data as possible, both stable and unstable. This profile is used to analyze patterns and improve fingerprinting on the front end. It is also used to identify and prevent network abuse. If you receive a tag of sus
or bad
, it means that your fingerprint was identified as highly suspicious and easily trackable, even with any anti-fingerprinting measures taken.
Rate-Limits
The challenge, if you choose to accept it, is to avoid getting put on timeout or banned.
/analysis
API simulates cost, but it does not implement a timeout./decrypt
API is delayed for less than a minute, the token cost will be doubled. Requests to this API are sent only at the start of a session or when the fingerprint changes (if the API is not locked).stable
, loose
, fuzzy
, & shadow
), masked network ip address, system location, dates, and other fingerprint data displayed on the websitePurpose: learn and predict browser engine and platform version, device, and gpu
{
cleanup: false,
decrypted: "Blink",
devicePrimary: "Windows 10 (64-bit)",
deviceTrust: `{
"Windows:Windows 10 (64-bit)": ["6a9","fe3","bb7"],
"Windows:Windows 7 (64-bit)": ["8a3"],
"Windows:Windows 11 (64-bit)": ["e4a"]
}`,
devices: [
"Windows:Windows 10 (64-bit)",
"Windows:Windows 7 (64-bit)",
"Windows:Windows 11 (64-bit)"
],
gpuBrands: [
"INTEL"
],
gpus: [
"INTEL:ANGLE (Intel(R) UHD Graphics Direct3D11 vs_5_0 ps_5_0)",
"INTEL:ANGLE (Intel, Intel(R) UHD Graphics 620 Direct3D11 vs_5_0 ps_5_0, D3D11)"
],
gpuWatch: [
"INTEL:460191600000:8/2/1984:703722......:18"
],
healEvents: [],
highEntropyLossYield: false,
highEntropyLost: true,
id: "01aa0cc74cd124b8985d7e386e5499b34770353cab321e214a2aae122b4c1995",
lock: false,
logger: [
"8eff_75d6295c_345026a9: Blink (2/5/1984, 2:54:02 AM)"
],
reporter: `{
"dates": ["2/5/1984","2/10/1984","2/17/1984","2/22/1984"],
"ips": ["8eff","66fa","6ac2","5887"]
}`,
reporterTrustScore: 100,
reviewed: true,
suggested: "no change",
systemCore: "unknown",
systems: [
"Windows"
],
systemWatch: [
"Windows:Windows:460191600000:8/2/1984:703722......:18"
],
timestamp: "1984-08-01T07:00:00.000Z",
trash: false,
type: "Canvas System",
userAgents: [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36"
]
}
Purpose: identify browser visit history and activity
{
bot: 0.125,
botHash: "00000001",
botLevel: "stranger:csl",
crowdBlendingScore: 36,
fingerprint: "18ce59ae1e65397c81b38da98e6eed23a8f6d4bd3a2a349ed800f7daebd6f9dc",
firstVisit: "1984-08-01T07:00:00.000Z",
fuzzyInit: "1879e559e5de22c3dceb603775ff8062bb274c41547f9fc0b38e919fc4000000",
fuzzyLast: "1879e559e5de22c3dceb603775ff8062bb274c41547f9fc0b38e919fc4000000",
lastVisit: "1984-08-01T07:00:00.000Z",
lastVisitEpoch: 460191600000,
looseFingerprints: [
"f331fd21a4f8dec8054ffaec88c32723f840f6a6174303cd787fb676a513bbf6"
],
looseSwitchCount: 0,
maxErrors: 0,
maxLies: 0,
maxTrash: 0,
score: 100,
scoreData: `{
"switchCountPointGain": 5,
"errorsPointGain": 0,
"trashPointGain": 0,
"liesPointGain": 0,
"measuredPointGain": 0,
"shadowBitsPointGain": 10,
"supervisedPointGain": 0,
"tracedPointGain": 0,
"grade": "A+"
}`,
shadow: "0000000000000000000000000000000000000000000000000000000000000000",
shadowBits: 0,
signature: "",
timeHoursAlive: 0,
timeHoursFromLastVisit: 0,
timeHoursIdleMax: 0,
timeHoursIdleMin: 0,
visits: 1,
benchmark: 565.4,
resistance: '',
traced: 0
supervised: 0,
}
SHA-256
hashing of stable fingerprint (Creep)FP-ID...: 9368a2b8913acba5633aa8f353bfd546aaaf77fd57c1416580e90fc41666feb2
Fuzzy...: 98fcf569e50680c3dcfb8e53e34874e2b2075c415208a1c05292119ec4000000
Diffs...: 50ed3569e50680c3dcfb8e00e3387c5fb2075c415408a2006292119ec4000000
Shadow..: 1111100000000000000000110010011100000000010001101000000000000000
A failing trust score is unique
The trust score shows the level of trust computed from the browser fingerprint values and revision indicators. If the score is 100%, there is a high level of trust in the reported values. Values should not be trusted when the score is low. It is not always beneficial to have a high trust score, and sometimes a low trust score is not bad.
100
20
loose fingerprints: reward 3
extra credit0.2
shadow bits (revision indicator): reward 4
extra credit20-39
loose fingerprints (revision indicator): subtract count * 0.1
40-99
loose fingerprints (revision indicator): subtract count * 0.2
100
or more loose fingerprints: subtract count * 0.5
0.1
or more shadow bits: subtract value * 15
count * 5.5
count * 31
count * 3.5
count * 25
(tracing involves time series fingerprinting)count * 10
(supervised is a special case of anomalies)crowdBlendingScore
to the above total and divide by 2platform = 'Cat OS'
gpu = ' Cat Adaptor'
// ¯\_(ツ)_/¯
userAgent = 'Chrome 102'
features = '101' // I disabled a feature
gpu = '^5zeD4 Cat Titan V' // We can forgive this
Proxy
or Object.defineProperty()
Window
scope values not matching WorkerGlobalScope
valuesWindow
values not matching HTMLIFrameElement.contentWindow
valuesMath
calculations or invalid DOMRect
coordinatesPerformance.now = function() {
// break the web
throw new Error('Crash the code before it starts!')
}
1
values (bits) in the shadow fingerprintbits = 4
totalBins = 64
shadowBits = bits/totalBins // 0.0625
A data set with only 1 reporter is unique and easy to trace
In the prediction section, the crowd blending score is a site indicator that scores how well certain fingerprints blend in with others (strictly collected on the same site).
100-(numberOfRequiredReporters ** (numberOfRequiredReporters - numberOfReporters))
-100
-64
-16
-4
Bots leak unusual behavior and can be denied services
Do we really know you are a bot? No, but we can have fun trying!
10000000:smart-enemy:lws
(lied worker scope)01000000:crafty-attacker:lpv
(lied platform version)00100000:stealth-hacker:ftp
(function toString proxy)00010000:clumsy-spy:ofv
(ua outside features version)00001000:bold-fraud:elc
(extreme lie count)00000100:hyper-client:elf
(excessive loose fingerprints)00000010:locked-down:wsb
(service & shared worker scopes blocked)00000001:stranger:csl
(crowd-blending score low)00000000:friend
(none of the above)// Cute cat trap. Works every time!
let clientIsBadBot = false
let banned = false
// How long did the client pause to admire the cute cat?
const catTime = await getClientTimeWithCuteCat()
if (catTime < 10000 /* 10 seconds */) {
clientIsBadBot = true
}
if (catTime < 1000) {
// client should get banned! Proceed with caution
// Agent could be extraterrestrial and friendly
banned = true
}
Loose fingerprint revision patterns can follow stable fingerprints like a shadow
WorkerNavigator.userAgent
and other stable fingerprintsGecko
, Goanna
, Blink
, WebKit
SpiderMonkey
, JavaScriptCore
, V8
window.Fingerprint
window.Creep
The loose fingerprint is used to detect rapid and excessive fingerprints
This is the main fingerprint, the creep
Contributions are welcome.
🟫 install yarn install
🟩 build yarn build:dev
🟪 watch yarn watch:dev
🟦 release to GitHub pages yarn build
If you would like to test on a secure connection, GitHub Codespaces is supported. It is discouraged to host a copy of this repo on a personal site. The goal of this project is to conduct research and provide education, not to create a fingerprinting library.