Slopsquatting: bestaat het package? Verkeerde vraag
9m leestijd

Slopsquatting: bestaat het package? Verkeerde vraag

Het standaardadvies tegen verzonnen packages luidt: controleer eerst of het package bestaat. Ik heb vier namen uit het nieuwste onderzoek opgezocht op PyPI. Ze bestaan alle vier. De registry beantwoordt de verkeerde vraag, en dat gaat in beide richtingen mis.

Vraag een model om een Python-tool die tabellen uit een PDF haalt, en de kans bestaat dat je pip install tabula terugkrijgt. Dat package bestaat. Het staat er nu nog, versie 1.0.5, en het is een formatter voor ASCII-tabellen van een auteur die niets met PDF's te maken heeft. Laatste release: november 2012.

Het package dat je zocht, heet tabula-py.

Ik heb vanmiddag vier namen opgezocht, op 2 september 2026. Ze komen uit een paper van 24 augustus, als voorbeelden van packagenamen die modellen verzinnen. Alle vier krijgen ze een HTTP 200 van PyPI.

Het model zegtAntwoord van PyPILaatste releaseWat je nodig had
pip install pil200, v1.1.66 releases, al lang stilpillow, release 1 juli 2026
pip install faiss200, v1.5.316 april 2019, één releasefaiss-cpu, release 3 augustus 2026
pip install tabula200, v1.0.51 november 2012tabula-py
pip install haystack200, v0.423 juli 2017haystack-ai, v3.1.0 op 24 augustus 2026

haystack op PyPI zoekt C-structs in het geheugen van een proces. De haystack die je agent bedoelt, is een framework om LLM-applicaties mee te bouwen. Ze delen een naam en verder niets.

Daar gaat het mis met het advies dat iedereen geeft.

Vier packagenamen die de registry goedkeurt maar die je nooit moet installeren, tegenover twee die hij onterecht afkeurt.

De controle die iedereen aanraadt, mist de helft

Slopsquatting is de aanval waarbij een model een packagenaam zo consequent verzint dat iemand die naam vóór je registreert en gaat zitten wachten. De tegenmaatregel komt in alle artikelen, ook de verstandige, op hetzelfde neer: controleer of het package echt bestaat voordat je installeert wat de agent voorstelde.

Dat advies heeft een concrete mechanische betekenis. Je vraagt het aan de registry. Krijg je een 404, dan is de naam verzonnen. Krijg je een 200, dan zit je goed.

De paper van 24 augustus vat het probleem in één zin samen:

An attacker who has already registered the hallucinated name trivially bypasses a pure 404 check.

De auteurs, Akash Raj en Sargam Sahu, bouwden juist een detector met twee lagen omdat één laag niet volstaat. Hun eerste bevinding maakt een einde aan de bestaanscontrole als verdediging: de helft van de hallucinaties die hun pijplijn markeerde, waren packages die al op PyPI stonden, als slappe aftreksels van bekende projecten. De deterministische laag miste ze allemaal. Een classifier die naar de naam en de metadata kijkt, ving ze wel.

pil, faiss, tabula en haystack zijn hun voorbeelden. Wat een 404-check je over die vier vertelt, staat hierboven: niets.

De controle faalt ook in de andere richting

Als hij alleen in die ene richting faalde, kon je hem als ondergrens gebruiken en verder gaan. Hij faalt in beide richtingen, en die tweede is precies waarom teams die dit automatiseren hun eigen tooling gaan negeren.

Een 404 betekent niet dat het model iets verzon. Frameworks leveren virtuele modules, gebundelde subpackages en import-aliassen die in de code kloppen en geen eigen vermelding in de registry hebben.

Dat is geen theorie. Toen de onderzoeker achter een grootschalige studie naar package-hallucinaties zijn npm-bevindingen niet via de eigen securitykanalen van de registry kwijt kon, stapte hij eind april naar Socket. Socket nam alle 18 npm-kandidaten door en publiceerde het resultaat in juli.

De vier namen die daarin het vaakst voorkwamen, waren @ember/service, @ember/object, @ember/routing en @ember/controller. Alle vier zijn geldige Ember-imports die via ember-source worden opgelost. Een model dat @ember/service uitspuugt, schrijft correcte Ember. Vraag je de registry naar die naam, dan krijg je een 404.

Socket vond daarnaast dat ssh-keys een bestaand package is en dat metro-evaluator al onder een security hold zat. Daarmee vielen zes namen af uit de exploiteerbare set, en de onderzoeker verwerkte de bevinding in versie 2 van de paper als een categorie valse positieven.

Ik heb dezelfde controle op mijn eigen machine gedraaid en kwam op kleine schaal tot dezelfde uitkomst.

Uit de lokale transcripts heb ik elk installatiecommando gehaald dat mijn agents in augustus 2026 voorstelden: 1.100 transcriptbestanden, 135 sessies, 121 aanroepen, 34 verschillende packagenamen. Daarna heb ik npm en PyPI naar elk van die namen gevraagd.

Precies één naam gaf een 404: argos-mcp. Dat is mijn eigen MCP-server, lokaal gekoppeld met npm link. Nooit gepubliceerd. De enige misser van de registry in een maand agent-output was een vals positief, en het was mijn eigen package.

Het aardigste zat in de ruis. Het script waarmee ik de transcripts uitkamde, was in zijn eerste versie grofmazig, en viste drie gewone woorden uit de lopende tekst van de agent die toevallig naast install stonden. De registry keurde ze alle drie goed. installation is een echt package, 23 versies, voor het laatst bijgewerkt in 2022. both is een echt package met één versie, 0.0.0, en als omschrijving letterlijk de tekst ERROR: No README.md file found!. En binaries geeft een 200 terug met nul gepubliceerde versies en geen enkele maintainer, een naam die in 2018 is vastgelegd en verder leeg staat.

Drie woorden die nooit packagenamen waren, doorgelaten door de controle die verzonnen packagenamen moest tegenhouden. En één echt lokaal package, tegengehouden.

Het gaat om 34 namen op de laptop van één ontwikkelaar, dus lees het als een illustratie en niet als een meting. Beide foutrichtingen kwamen er hoe dan ook uit.

Van model wisselen helpt niet

De reflex is om een tweede model het voorstel van het eerste te laten nakijken. Het onderzoek is opvallend helder over waarom dat tegenvalt.

Het onderzoek dat Socket nakeek, is een replicatie van het USENIX Security '25-werk over package-hallucinaties, losgelaten op vijf actuele modellen: Claude Sonnet 4.6, Claude Haiku 4.5, GPT-5.4-mini, Gemini 2.5 Pro en DeepSeek V3.2. Bijna 200.000 prompts. Naast de percentages per model werd er gezocht naar namen die alle modellen verzinnen, en dat leverde er 127 op. Van de 109 Python-namen bleven er na de verbodslijst en de normalisatie van PyPI Security nog 41 registreerbaar, en de controle van Socket bracht de npm-kant terug van 18 naar 12. Blijven over: 53 namen die alle vijf de modellen produceren en die een aanvaller ten tijde van de disclosure in april 2026 nog gewoon kon vastleggen.

Eén registratie. Gebruikers van vier leveranciers.

Drie van die namen staan open en bloot in de publicatie: css-color-stop, dns-sd en dom-ains. Ik heb ze alle drie opgezocht tijdens het schrijven. Twee ervan zijn nog vrij.

css-color-stop is op 28 juli 2026 geregistreerd, zes dagen nadat Socket het artikel publiceerde waarin die naam stond. Wat er nu staat is versie 0.0.0: één bestand, 53 bytes uitgepakt, geen dependencies, geen install-script, geen README, geen omschrijving.

Zo ziet een defensieve registratie eruit: een leeg package waarin niets draait. Dat is ook de waarschijnlijkste lezing. Iemand las de publicatie en legde de naam vast zodat een ander dat niet kon. Toch is het de moeite waard om er even bij stil te staan, want het mechanisme is in beide gevallen hetzelfde. Een naam ging in zes dagen van openbare publicatie naar vastgelegd npm-package, en het enige verschil tussen de onschuldige variant en de andere zit in wat er in die tarball wordt gestopt.

Die 53 is het getal waar het om draait, en geen onderzoek naar één model had ze kunnen vinden. Gemini het huiswerk van Claude laten nakijken helpt niet als ze dezelfde naam verzinnen. De paper van 24 augustus meet de variant daarvan binnen één modelfamilie: komen het primaire model en zijn fallback uit dezelfde familie, dan keert ongeveer 84% van de missers van het eerste model terug bij het tweede.

Het getal dat iedereen citeert is verlopen

Terwijl ik me hierin inlas, kwam ik op vrijwel elke blog en leverancierspagina dezelfde twee cijfers tegen: 19,7% van de gegenereerde packages bestaat niet, en 43% van de verzonnen namen komt bij alle tien de herhalingen terug. Die komen uit Spracklen et al., dat in 2024 als preprint rondging en op USENIX Security '25 is gepubliceerd.

De replicatie meet bij de huidige frontier-modellen 4,62% tot 6,10%. Het verschil tussen het beste en het slechtste model kromp van 16,5 procentpunt naar 1,48.

Wie in september 2026 nog 19,7% aanhaalt, beschrijft een modelgeneratie die inmiddels is opgevolgd. Daar zit wel een keerzijde aan. Het percentage daalde en de vorm van het risico werd erger, want de modellen groeiden naar elkaar toe. Als het model van elke leverancier dezelfde 127 namen verzint, is het werk van de aanvaller geen kansspel meer.

Lees ook de kanttekeningen, want de studie plaatst er zelf een paar. GPT-5.4-mini is getest met minimale reasoning effort en weigerde 32% van de prompts, dus zijn percentage is berekend over wat overbleef. De metingen beslaan één week in april op specifieke modelversies. En agents die de registry raadplegen voordat ze een dependency voorstellen, gedragen zich anders dan een model dat één prompt beantwoordt. Dit blijft een preprint met een correctie van een leverancier erin verwerkt, en dus verre van uitgekristalliseerde wetenschap.

Waar je wel op let

Bestaan is de verkeerde vraag. Dit zijn de vragen die de vier namen uit mijn openingstabel wél scheiden van hun echte tegenhangers:

  • Wanneer was de laatste release? Alle imitaties hierboven liggen stil: 2012, 2017, 2019. De echte hebben allemaal in de afgelopen twee jaar nog een release gehad. Stilstand plus een naam die je agent net voorstelde, is het sterkste goedkope signaal dat er is.
  • Hoeveel releases, en hoeveel maintainers? Eén release en geen maintainer is geen project. binaries heeft nul versies en geeft een 200.
  • Past de omschrijving bij wat je vroeg? haystack zegt dat het C-structs in procesgeheugen zoekt. Jij vroeg om een LLM-framework. De registry vertelde je de waarheid, en de controle gooide die weg door alleen naar de statuscode te kijken.
  • Komt de importnaam overeen met de installatienaam? import cv2 installeert opencv-python. Die mismatch is doodnormaal in Python, en juist daarom kan een naamgenoot zich er prima in verstoppen.
  • Commit je lockfile en installeer daaruit in CI. Dat is dezelfde redenering als bij een versie vastzetten is niet hetzelfde als een commit vastzetten. Een lockfile houdt drift tegen bij packages die je al gecontroleerd hebt. Tegen de eerste installatie doet hij niets, en dat is precies het moment waarop slopsquatting toeslaat.
  • Behandel een dependency die je agent voorstelt als een pull request van een vreemde. De checklist voor MCP-servers vóór installatie kost dezelfde tien minuten, alleen bij een andere registry.

Nieuw is dat allemaal niet. Het is de controle die npm ons allang geleerd heeft en die we overslaan zodra het voorstel van iets komt dat zelfverzekerd klinkt.

En dat is het echte mechanisme. Het model zegt er niet bij dat het naar een packagenaam gokt, want het gokt niet. Het produceerde de meest plausibele voortzetting, en een plausibele packagenaam ziet er precies uit als een echte. Daar zit het hele aanvalsoppervlak. tabula is een betere naam dan tabula-py. Daarom grijpt het model ernaar, en daarom legde iemand die naam in 2012 al vast voor iets heel anders.

De registry bevestigt dat het bestaat. Dat het model ernaast zat, hoor je er niet bij.

(33 van 33)
01Je hebt geen AI-probleem. Je hebt een procesprobleem.02Waarom je nooit code moet shippen die je zelf niet snapt03Stop met copy-paste engineering04De lavalaag: waarom AI-code je codebase langzaam versteent05De prompt is geen spec06Het briljante papegaai-probleem: wat AI eigenlijk doet als het 'denkt'07De bureaucratie van bots: waarom we de controleur controleren08De wapenwedloop om je vertrouwen: Mythos, Cyber en de security-hype09Laat je agents stoppen met Markdown schrijven10Je vindt de bug niet als je de code niet schreef11Een op vier: de beveiligingsschuld die niemand telt12Je 10x-developer zit vast in een 0,1x-pipeline13Caveman vs context-mode: kleinere mond, of kleinere kamer?14Code churn: de lava die je nog kunt meten15Het plafond is van beton16De token-belasting: ik trek mijn Caveman-advies in17Zelfs de malware is nu AI-slop18ThePrimeagen had gelijk19Tokenmaxxing: wat er gebeurt als je het verkeerde meet20Ze vroegen het de bot gewoon netjes: je supportagent is het aanvalsoppervlak21Snelheid werd goedkoop. Je oordeel niet.22De Ferrari heeft een begrenzer: een dag met Claude Fable 523De uitknop was nooit van jou24Een open MCP-server is erger dan een open database25De uitknop werkt nu ook andersom26AI genereert je tests. Maar test het ook echt?27Beter code leren lezen: een oefenroutine28Programmeren leren in het AI-tijdperk: wat ik als eerste zou leren29Wie is verantwoordelijk voor AI-code? Jij, en sinds dit jaar staat het zwart op wit30Wanneer je beter geen AI gebruikt bij programmeren: het werk dat ik zelf blijf doen31Junior developers aannemen in 2026: de instroom stopte, en dat was een keuze32Software inschatten met AI: het typen was nooit waar de tijd in zat33Slopsquatting: bestaat het package? Verkeerde vraag