Detection methodology
Six detection methods, each with rules anyone can audit and replicate. Source code MIT.
#1
Funding-source clustering
apps/ml/sybilshield/clustering/funding_cluster.py
- · Group addresses by their first incoming (non-CEX) funder
- · Filter out groups with <3 members
- · Confidence scales by time spread of the funding events: <24h → 0.95, <7d → 0.80, else 0.60
- · CEX hot wallets (Binance, Coinbase, etc.) are explicitly excluded
#2
Behavioral clustering
apps/ml/sybilshield/clustering/behavior_cluster.py
- · Build 10-feature vector per address (timing, entropy, protocol diversity, etc.)
- · Drop zero-variance columns (sigma < 1e-12) to prevent uniform-input failure
- · z-score normalize, then HDBSCAN with min_cluster_size=5, leaf cluster selection
- · Fallback: if HDBSCAN returns all-noise AND ≥3 features have zero variance across the batch, treat the whole batch as one Sybil cohort (real-world catch for uniform-script farms)
- · Intra-cluster spread → confidence (lower spread = higher confidence)
#3
Graph community detection
apps/ml/sybilshield/clustering/graph_community.py
- · Build directed weighted graph from in-batch transactions (igraph backend, scales to 500K+ nodes)
- · Run Leiden algorithm via leidenalg (RBConfigurationVertexPartition, resolution=1.0, seed=42)
- · Filter communities by size (5 ≤ n ≤ 500) and density (≥ 0.3)
- · Both size and density bounds matter: dense rings are Sybil, but legitimate DEX-using groups also form communities — density threshold cuts them
#4
Cross-chain identity linking
apps/ml/sybilshield/clustering/cross_chain.py
- · Deterministic: bridge tx from address A on chain X to address B on chain Y → same entity by construction (Stargate, Hop, Across, Wormhole)
- · Probabilistic: same funder + same timestamp window (±10min) across chains → likely-same entity
- · Union-find aggregates into entity components
- · Cluster fires when ≥3 chain-nodes belong to one entity
#5
Temporal anomaly features
apps/ml/sybilshield/features/temporal.py
- · Hour-of-day entropy (humans: > 2.5, bots: < 1.5)
- · Day-of-week entropy
- · Min inter-tx seconds (humans rarely < 60s)
- · Burst score (proportion of txs concentrated in 10% of activity window)
- · Lag-1 autocorrelation of inter-tx gaps (mechanical regularity)
- · Activity ratio (active days / account age days)
#6
ML ensemble scoring
apps/ml/sybilshield/scoring/train.py
- · LightGBM binary classifier with class_weight='balanced'
- · Sample-weighted by confidence tier (T1=4.0, T4=0.8, G1=4.0, G2=2.0)
- · Trained on ALL tiers (T1-T5 + G1-G2 with weights)
- · Evaluated on T1+T2 sybil + G1 genuine holdout ONLY - never against T4 detector outputs (which are themselves noisy)
- · Honest metrics published: P@70, R@70, FPR-on-G1, ROC-AUC, adversarial recall
Label tier system
We do not pretend our labels are perfect. Each labelled address has a tier:
| Tier | Confidence | Source example |
|---|---|---|
| T1 | 0.98 | Confessed via amnesty (LayerZero, Optimism) |
| T2 | 0.95 | Manually investigated (Hop, security researchers) |
| T3 | 0.85 | Multiple detectors agree |
| T4 | 0.65 | Single detector output (raw Arbitrum/Linea lists) |
| T5 | 0.75 | Self-derived heuristic (shared funder same block) |
| G1 | 0.95 | Verified human (Gitcoin Passport ≥20 stamps) |
| G2 | 0.80 | Likely human (ENS pre-2021 + active history) |
What we DON'T do
- · Score based on token holdings or wealth
- · Penalise addresses for using mixers or privacy tools per se
- · Flag addresses just because they hold a Worldcoin orb proof or any other "humanness" credential
- · Publicly list any individual address as Sybil — only aggregates
- · Train on labels from other commercial detectors (they may be wrong)
- · Charge for the appeal process
Reproducibility
Every model artifact stores its feature_schema_hash and training_manifest_hash. If you can't reproduce a score from the published artifact + manifest hashes, the score is invalid.