TL;DR
Het meeste geautomatiseerde verkeer is makkelijk te stoppen. Een user-agent-reguliere expressie en een CAPTCHA vangen de onderkant van de markt. Het verkeer dat ertoe doet leeft daar niet. Stealth-gepatchte browsers, residentieel-geproxyde scrapers en LLM-aangestuurde agents draaien echte browser-engines, dragen schone fingerprints en bewegen een aanwijzer zoals een mens dat doet. Een schone fingerprint bewijst geen mens, en een datacenteradres bewijst geen bot.
Dit is een veldrapport over een detectiestack die voor die tegenstander gebouwd is: een deterministische regellaag plus twee compacte neurale modellen, één die fingerprint- en netwerksignalen leest en één die gedrag leest, gecombineerd door een logische OR. De bevroren embedding van het gedragsmodel scheidt bots vrijwel perfect van mensen. Een zoektocht over 16 architecturen laat zien dat het prestatieplafond van het signaal komt, niet van het model. En het eerlijke resultaat: op de volledige productiepopulatie bij een strikt false-positive-budget zit de recall onder de lat die de stack op zijn trainingsverdeling haalt, om redenen van populatiesamenstelling in plaats van modelkwaliteit.
Specifieke detectiesignalen, featurenamen en drempelwaarden worden bewust achtergehouden, zodat het engineeringwerk reproduceerbaar is in geest zonder een ontwijkingsgids te worden.
De tegenstander waar het de moeite waard is om tegen te bouwen
Een user-agent-regex en een CAPTCHA stoppen de onderkant van de automatiseringsmarkt en laten de rest door. De tegenstanders waar het de moeite waard is om tegen te bouwen zitten niet in die onderste laag. Ze draaien echte Chromium. Ze patchen het fingerprint-oppervlak dat naïeve checks uitlezen. Ze proxyen via residentiële adresruimte. De meest capabele zijn taalmodel-agents die een doel nastreven over een meerstaps flow in plaats van een vast script af te spelen.
De bepalende eigenschap van deze tegenstander is dat geen enkele waarneembare grootheid de vraag beslist. Dit is dezelfde reden waarom CAPTCHA's geen echt werk meer doen tegen gemotiveerde automatisering, en waarom stealth en anti-detect browsers als productcategorie bestaan. Je kunt het antwoord niet van één waarde aflezen. Je moet onafhankelijke signalen combineren en accepteren dat elk afzonderlijk soms fout is.
De detectiestack: een deterministische laag en twee compacte modellen
De stack beslist of een bezoeker geautomatiseerd is met een tweetraps cascade voorafgegaan door een deterministische regellaag.
- Deterministische regellaag. Codeert het handjevol condities dat op zichzelf bewijs van automatisering vormt.
- Model 1, fingerprint (MorphNet). Scoort een enkele pagina-evaluatie op basis van apparaat-, browser- en netwerksignalen.
- Model 2, gedrag (GammaNet). Scoort een hele sessie op basis van gedragstelemetrie, en neemt de score van het eerste model als input.
Het uiteindelijke label is de logische OR van alle drie. Een bezoeker wordt gemarkeerd als de regellaag vuurt, of als een van beide modellen vuurt. Die structuur heeft een gevolg dat al het andere vormgeeft: omdat de regellaag de gevallen die hij kan bewijzen al vangt, hoeven de modellen dat niet. De modellen trainen alleen op de rest, het verkeer dat de regels niet kunnen beslechten, wat zowel het moeilijke deel van het probleem is als het deel waar een model zijn plek verdient.
De lat die overal wordt aangehouden is een recall van minstens 0.90 bij een false-positive-rate van hoogstens 0.01, gemeten op echt productieverkeer op sessieniveau.
Hoe de evaluatie eerlijk blijft
De getallen hieronder betekenen alleen iets door hoe de evaluatie is opgebouwd, dus het is de moeite waard om eerst de waarborgen te benoemen.
Trainings- en evaluatiedata zijn echte pagina-evaluaties gegroepeerd in sessies. Labels zijn deterministisch, alleen toegepast wanneer een signaal bewijs vormt; alles wat dubbelzinnig is wordt ongelabeld gelaten in plaats van geraden, wat labelruis uit de grondwaarheid houdt. Voor de stealth-klassen die fingerprinting per constructie ontwijken, komt de grondwaarheid van een gecontroleerde verkeersgeneratie-harness die bekende automatisering tegen geïnstrumenteerde doelen draait, zodat het label bekend is door herkomst in plaats van afgeleid.
Drie lekkagewaarborgen houden de gerapporteerde getallen eerlijk:
- De signalen die de deterministische regellaag leest, worden uitgesloten van modeltraining, zodat het model de rest leert in plaats van te hermemoriseren wat de regels al bezitten.
- De events die direct een automatiseringsagent aankondigen, worden uit de gedragsstroom verwijderd voordat features worden berekend, zodat het gedragsmodel beweging- en timingstructuur leert in plaats van de aanwezigheid van een verraderlijk eventtype.
- De cascade is bedraad met out-of-fold scores: de bijdrage van het eerste model aan het tweede is zijn cross-gevalideerde score, nooit een voorspelling van een model dat de sessie al gezien heeft.
Elke split is per sessie, nooit per rij, aangezien meerdere evaluaties een sessie delen en een split op rijniveau dezelfde sessie aan beide kanten zou laten verschijnen. Alle resultaten gebruiken een vaste seed.
Model 1: MorphNet, het fingerprintmodel
Het eerste model leest ruwweg 90 features per evaluatie die fingerprintcoherentie, transportlaagkenmerken en netwerkcontext beschrijven. De eerste productieversie was een gradient-boosted tree-ensemble. Het was accuraat op makkelijk verkeer, zwaar om in een latentiegevoelig verzoekpad uit te leveren, en moeilijk te introspecteren. Het werd vervangen door een vanaf-de-grond gebouwd netwerk.
MorphNet geeft een klein netwerk de expressieve vorm van een tree-ensemble: een geleerde lineaire reductie naar een compacte interne ruimte, dan activaties per kanaal waarbij elk kanaal zijn eigen responscurve aanmeet, dan een low-rank interactielaag die paren signalen elkaar laat moduleren, een gewogen uitlezing, en een korte trechter naar één output. Het hele model is ongeveer 6,500 parameters en traint in ruwweg 25 seconden op een laptop-GPU.
Twee latente fouten in de eerste opzet werden bij de ontwerpreview gevangen, voordat er ook maar trainingscode geschreven was. De ene was een terminale softmax over een enkele output, wat wiskundig constant is en geen gradiënt draagt, zodat het model niet kon leren. De andere was een interactie-uitlezing die instortte tot een constante vector, een dode laag die niets bijdraagt. Een derde les kwam uit de training: de keuze van normalisatie is dragend. De lopende statistieken van batchnormalisatie lieten de validatie-AUC zakken van 0.99 naar 0.50, en layernormalisatie is de juiste keuze voor het enkel-voorbeeldmodel dat in productie draait.
Op een eerlijke split op sessieniveau, MorphNet-resultaten:
| Metric | Value |
|---|---|
| AUC | 0.9994 |
| Recall op werkpunt | 0.9959 |
| Recall over 5 seeds | 0.9962 ± 0.0007 |
| Numerieke overeenkomst inference-vs-training | within 5e-7 |
Elke seed haalt de poort, en de overeenkomst tussen de geëxporteerde inferentiegraaf en het trainingsframework betekent dat het uitgeleverde model het getrainde model is.
Het contrast met de oude baseline is het scherpst op de resterende moeilijke set, het verkeer dat de regellaag niet kan beslechten. Op een achtergehouden stress-split van 6,004 sessies:
| Model | Recall op resterende moeilijke set |
|---|---|
| Eerdere gradient-boosted versie A | 0.139 |
| Eerdere gradient-boosted versie B | 0.039 |
| MorphNet | 0.996 |
De herbouw is geen marginale winst op deze slice. Het is het verschil tussen een model dat op de moeilijke gevallen werkt en twee die dat niet doen.
Model 2: GammaNet, het gedragsmodel
Gedrag is moeilijker dan fingerprint, dus het tweede model heeft meer structuur. Het leest 179 geaggregeerde gedragsinputs die de vorm van een sessie beschrijven, en het is opgebouwd uit twee onderdelen.
De voorkant is een autoencoder-encoder die de opgeschoonde, gestandaardiseerde inputs omlaag brengt via een verborgen laag naar een 32-dimensionale latente vector op de eenheidshypersfeer. Deze encoder wordt één keer getraind, zonder labels, en daarna bevroren. De achterkant is een kleine gesuperviseerde kop: elk latent kanaal gaat door een compacte geleerde nonlineariteit, geïnitialiseerd zodat de training begint vanaf de bevroren representatie, gevolgd door een korte lineaire trechter naar één output. Het model telt ongeveer 14,000 parameters, het leeuwendeel ervan in de bevroren encoder en slechts een paar honderd trainbaar in de kop.
De encoder bevriezen is de beslissing die dit model laat gedragen. Een encoder die getraind is om te reconstrueren generaliseert naar live verkeer; een die getraind is om de klassen zo scherp mogelijk te scheiden doet dat niet. Op een achtergehouden split op sessieniveau bereikt GammaNet een AUC van 0.9989 en een recall van 0.9964 op het werkpunt, op een haar na een vers hertrainde tree-baseline op de identieke split. Op een live replay tegen bekende bots was zijn model-only recall 99.4%, tegen 96.4% voor het eerder ingezette gedragsmodel.
De gedragsembedding scheidt vrijwel perfect
Het meest opvallende artefact van het project is de geometrie van GammaNet's bevroren latente ruimte. Ruwweg 17,000 sessies werden door de encoder in kaart gebracht om te zien waar bots en mensen landen. Ze zitten in tegenovergestelde gebieden van de sfeer.
| Metric | Value | What it means |
|---|---|---|
| Nearest-neighbour-zuiverheid (k=1) | 99.6% | Bijna elk punt zijn dichtstbijzijnde buur deelt zijn klasse |
| Cosinus-scheiding van zwaartepunten | -0.99 | Bot- en mens-zwaartepunten zitten bijna antipodaal op de sfeer |
| Gemiddelde lokale entropie (k=20) | 0.010 | Vrijwel geen klassevermenging in lokale buurten |
In de praktijk is er geen verwarringszone. De klassen zitten bij tegenovergestelde polen, het gebied tussen hen bevat vrijwel geen kansmassa, en het model is bijna overal zelfverzekerd.
De projectie hieronder maakt die geometrie tastbaar: elk punt is een sessie die door de bevroren encoder in kaart is gebracht, en de synthetische stressvariaties trekken weg van het echte-veldcluster in plaats van erin op te gaan. Sleep om te draaien.
De scheiding is niet het werk van één enkele richting. Wanneer elke latente as op zichzelf gescoord wordt, is het onderscheidend vermogen verspreid over de representatie, met een dozijn of meer assen die elk echt signaal dragen in plaats van één as die het werk doet. Die verdeling is van belang voor een beveiligingsmodel. Een representatie die haar signaal in één as concentreerde, zou ook het doelwit van de tegenstander concentreren. Een verdeelde biedt dat enkele punt om op te duwen niet.
De architectuurzoektocht, en een muur
Dit is het punt waar een uiteenzetting meestal de overwinning uitroept. Het tegenovergestelde gebeurde: een poging om het model te verslaan. Als 32 dimensies de klassen zo schoon scheiden, zou een rijkere embedding de live prestaties misschien nog verder kunnen verhogen.
De test was een vergelijking van 16 modelfamilies op de gedragsfeatureset, gescoord op een batterij die de live productietaak omvatte. De set was bewust breed: variational autoencoders van verschillende soorten, gesuperviseerd-contrastieve en hypersferische doelstellingen, rotatie-geparametriseerde en feature-groep-gefactoriseerde encoders, quaternion- en octonion-hypercomplexe backbones, denoising- en contractieve varianten, en een self-attention-transformer over featureblokken.
Twee bevindingen kwamen terug, en beide waren duidelijk.
Ten eerste is het live plafond invariant onder architectuur. Elke familie, van een gewone tied autoencoder tot een octonion-netwerk tot een transformer, landde in een smalle band, en de beste ervan evenaarde slechts de bestaande encoder. Architecturale verfijning verschoof de grens niet.
Ten tweede ging scherpere scheiding in-verdeling gepaard met slechtere live generalisatie. De modellen met de scherpste split op de trainingsverdeling, de agressieve contrastieve doelstellingen die perfecte recall op de trainingsdata bereikten, behoorden tot de zwakste op live verkeer. De trainingsverdeling overscheiden is overfitting onder een andere naam, wat precies de reden is dat de encoder bevroren is in plaats van hervormd door de classifier.
Dan de controle die de vraag beslechtte: gooi de embedding helemaal weg en train classifiers rechtstreeks op de ruwe features. Een onbeperkte gradient-boosted tree die elke ruwe feature zonder bottleneck krijgt, een lineair model op dezelfde features, en de compacte embedding landen allemaal op vrijwel dezelfde live AUC: een hard plafond dat we gemeten hebben in plaats van aangenomen. Het live plafond is een eigenschap van wat je meet en niet van hoe je het modelleert. Dat is een nuttiger resultaat dan nog een decimaal AUC, want het zegt, met bewijs, dat verder modelleerwerk op de huidige signalen een doodlopende weg is, en dat de weg vooruit een nieuw en onafhankelijk signaal is.
Eén voetnoot werd een model. Aangezien de beste generalisatoren de generatieve koppen waren, bouwde het team er een. VMFNet scoort een sessie met een von Mises-Fisher-mengsel per klasse op de sfeer, en vergelijkt de waarschijnlijkheid onder een menselijk mengsel met die onder een botmengsel. Met ongeveer een derde van de omvang van de eerdere embeddingstack bereikt het hetzelfde ruwe-feature-plafond. Generatieve koppen generaliseerden stabieler dan discriminatieve, dezelfde les die leidde tot het bevriezen van de encoder.
Defense in depth: lagen die onafhankelijk falen
Accuratesse in-verdeling is op zichzelf een zwakke garantie, dus elk model werd intern red-teamed tegen inputverstoring en gedeeltelijke telemetrie. De verstoringsbudgetten worden achtergehouden, aangezien die getallen neerkomen op een recept, maar het kwalitatieve beeld stuurt het ontwerp. Het fingerprintmodel degradeert gracieus onder gematigde inputruis en tolereert onvolledige telemetrie, wat een verzoekpad-model nodig heeft als het soms gedeeltelijke data ziet.
De conclusie waarop het ontwerp handelt is dat geen enkel model het systeem mag dragen. Dat is waarom de stack een cascade is in plaats van één classifier. Een tegenstander die het sterkste bewijs van één model degradeert, staat nog steeds tegenover de deterministische laag en een tweede model dat een geheel andere familie van signalen leest, en de uiteindelijke beslissing vuurt als een van de drie dat doet. Veerkracht komt hier voort uit het tegelijk vasthouden van meerdere ongecorreleerde aanwijzingen in plaats van één sterke. De stack verslaan betekent ze allemaal samen verslaan.
Productievoetafdruk
Omdat de stack vanaf het begin voor het verzoekpad ontworpen was, is de neurale versie zowel licht als accuraat.
| Measure | Tree-stack | Neurale stack | Change |
|---|---|---|---|
| Schijfgrootte (ONNX) | 6.465 MB | 0.079 MB | ongeveer 82x kleiner |
| Toegevoegd inferentie-RAM | +89 MB | +14 MB | ongeveer 6.4x lichter |
| Doorvoer | 0.56 M rows/s | 1.74 M rows/s | ongeveer 3x sneller |
De metric die ertoe doet houdt stand terwijl de voetafdruk met bijna twee ordes van grootte daalt. Het volledige ingezette gedragsmodel is 79 kilobytes, klein genoeg om als verwaarloosbaar te behandelen tegen de rest van het verzoekpad.
Dekking per klasse, en het eerlijke getal
Op de gouden standaard-evaluatie, 5,997 gelabelde bots en 7,964 mensen getrokken uit productielogs met splits op sessieniveau en lekkagewaarborgen, vangt de ingezette cascade elke tegenstanderklasse met volledige recall.
| Adversary class | Deployed-stack recall |
|---|---|
| Basisautomatisering | 100% |
| Harde stealth browsers | 100% |
| LLM-agents | 100% |
| Stealth + fingerprintpatch | 100% |
| Niet-gemapte live bots | 100% |
Dat omvat de moeilijke klassen: stealth browsers met gepatchte fingerprints, taalmodel-agents, en live bots die zich gedragen als gewone gebruikers. Sessies die een eerder model bijna nul scoorde, scoren nu bijna één na een gerichte fix voor de verdeling waar ze vandaan kwamen.
Dan het resultaat dat het werk eerlijk houdt. Op het strikte werkpunt zit de recall op de volledige productiepopulatie onder de lat die de stack op zijn trainingsverdeling haalt. De reden is het waard om duidelijk te benoemen, want het is geen probleem van modelkwaliteit. Het gat gaat over populatiesamenstelling en de kosten van een strikt false-positive-budget. Een echte menselijke populatie bevat grote groepen waarvan het verkeer bij dat budget op automatisering lijkt, dus dat vasthouden laat noodzakelijkerwijs recall liggen. De architectuurzoektocht liet al zien dat vrijwel al het scheidende signaal dat de huidige features bevatten is geëxtraheerd. Het resterende gat dichten vraagt om een nieuw en onafhankelijk signaal, of om populatiespecifieke werkpunten, in plaats van een betere classifier op dezelfde inputs.
Wat dit betekent voor teams die detectie draaien
Strip de specifieke details en een paar operationele lessen dragen over naar elk team dat mensen probeert te scheiden van automatisering die gebouwd is om er menselijk uit te zien:
- Fingerprint-only en netwerk-only checks missen de tegenstander die ertoe doet. De klassen die je geld kosten doorstaan die checks per ontwerp. Gedrags- en runtimesignalen zijn waar ze zich scheiden.
- Het plafond is het signaal, niet het model. Wanneer een modelzoektocht convergeert op hetzelfde getal over 16 families, zal meer modelleren niet helpen. De volgende winst komt van een nieuw, onafhankelijk signaal dat wordt vastgelegd waar de bot daadwerkelijk uitvoert.
- Bouw lagen die onafhankelijk falen. Een cascade van een deterministische laag plus ongecorreleerde modellen is moeilijker te ontwijken dan één sterke classifier, omdat een aanvaller ze allemaal tegelijk moet verslaan.
- Kies werkpunten per populatie en per actie. Een enkele globale drempel bij een strikt false-positive-budget laat recall liggen. Beperk de beslissing tot de actie, en stem het budget af op wie je beschermt.
Dit is ook waar cside operationeel past. cside houdt de browserruntime in realtime in de gaten, legt het apparaat en het echte client-IP vast, brengt runtime-script- en automatiseringssignalen aan het licht, leest fingerprintcoherentie en sessiecontinuïteit, en markeert AI-agents en stealth browsers binnen de pagina, en stelt die signalen vervolgens beschikbaar via een API zodat je een beslissing om toe te laten, te monitoren, uit te dagen of te blokkeren in je eigen workflow kunt aansturen. Die telemetrie op browserniveau is precies het onafhankelijke signaal waar een fingerprint-only of netwerk-only stack tegenaan loopt, en de laag waar een mens, een goede bot en een kwaadaardige agent eindelijk niet meer op elkaar lijken. Voor de signaalmechaniek onder die beslissing, zie de gids voor het detecteren van AI-agentverkeer en hoe je AI-agents op je website blokkeert.
Verder lezen op cside
- Gids voor het detecteren van AI-agentverkeer op je website
- Stealth browsers en anti-detect browsers, uitgelegd
- Waarom CAPTCHA's dood zijn
- Hoe je AI-agents op je website blokkeert
- cside AI-agentdetectie
Cijfers en metrics in dit rapport zijn afkomstig van gecachte modelartefacten en evaluaties op productieverkeer. Specifieke detectiesignalen, featurenamen en beslissingsdrempels worden bewust achtergehouden.





