Enverinament de paquets npm: anatomia d'una crisi de la cadena de subministrament
El 8 de setembre de 2025, un desenvolupador que es fa dir Qix va rebre un correu que semblava de npm. L'avisava, amb to d'urgència, que havia d'actualitzar les credencials del segon factor abans que li bloquegessin el compte. Era un matí de pressa, ho va llegir des del mòbil i va fer el que fem tots quan tenim quinze coses al cap: va clicar l'enllaç i va escriure l'usuari, la contrasenya i el codi temporal en una pàgina de login que no era la de npm. Setze minuts després, uns atacants publicaven versions enverinades d'una vintena de paquets npm que ell mantenia. Entre tots sumaven més de dos mil milions de descàrregues setmanals.
Aquell matí resumeix bé què és avui l'enverinament de paquets a npm: un dels vectors d'atac a la cadena de subministrament de programari que més ha crescut els darrers anys —el 2025 en va ser el punt d'inflexió, confirmant una tendència que feia temps que s'intensificava—, i un dels més difícils de defensar, perquè no explota cap error de codi sinó la confiança. El poder d'un paquet npm rau en el fet que aquests són programes dels quals depenen altres programes, instal·lats milions de vegades a tota mena de sistemes: des de l'ordinador d'un estudiant fins als servidors d'un banc. Sovint comprometre un equip és la porta d'accés a tota la xarxa corporativa.
Un cop dins, la càrrega maliciosa fa una d'aquestes coses, o diverses alhora: robar criptomonedes reescrivint adreces de cartera al vol, endur-se secrets —tokens, claus, credencials— que facilitin el següent atac, instal·lar una porta del darrere per tornar-hi quan convingui, o fins i tot reproduir-se sola i saltar al paquet següent. El fil que ho uneix gairebé sempre és el mateix: que al final de la cadena hi hagi diners.
El guió es repeteix amb poques variacions. Primer s'infecta o es suplanta el paquet, per alguna de les vies que veurem: el robatori del compte d'un mantenidor, un nom que imita el d'una biblioteca coneguda o, cada cop més, un nom que no existia fins que una intel·ligència artificial se'l va inventar i algú el va córrer a registrar. Després ve la propagació: desenes o centenars de projectes que en depenen comencen a baixar-lo automàticament, sovint sense que ningú se n'adoni. En algun moment de la instal·lació —sovint sense intervenció humana— es detona la càrrega i s'executen els processos que els atacants han orquestrat. I al final, si l'atac ha reeixit, les dades o les monedes canvien de mans en silenci.
Un degoteig de casos
eslint-scope (juliol de 2018)
Un dels primers informes de suplantació d'un mantenidor de paquet npm data del 2018, el paquet en qüestió va ser l'ESLint, probablement mitjançant credencials reutilitzades trobades en una filtració de tercers. L'atacant va publicar la versió 3.7.2 del paquet eslint-scope a les 10:40 UTC amb un script postinstall maliciós que exfiltrava el token d'autenticació del fitxer .npmrc local a servidors remots. npm va revocar tots els tokens generats abans de les 12:30 UTC. El CTO de npm, C.J. Silverio, va declarar que els tokens d'accés d'uns 4.500 comptes podrien haver estat obtinguts, tot i que no van trobar evidència que s'utilitzessin. eslint-scope tenia més de 2 milions de descàrregues setmanals.
ua-parser-js, coa i rc (octubre–novembre de 2021)
El 22 d'octubre de 2021, ua-parser-js (~7-8 milions de descàrregues setmanals, usat per Facebook, Microsoft, Amazon i altres) va ser segrestat: es van publicar tres versions malicioses (0.7.29, 0.8.0, 1.0.0) que instal·laven criptominers (XMRig) i troians de robatori de credencials a Windows i Linux, mitjançant un script preinstall.js. Rapid7 va identificar un fil en un fòrum de hacking rus del 5 d'octubre de 2021 oferint accés a un compte de desenvolupador d'un paquet amb "més de 7 milions d'instal·lacions". Poques setmanes després, el 4 de novembre de 2021, els paquets coa (~9 milions de descàrregues setmanals) i rc (~14 milions) van ser segrestats amb malware gairebé idèntic (una variant de DanaBot). Els desenvolupadors ho van detectar quan els seus builds de React van començar a fallar. Els tres paquets sumaven més de 28 milions de descàrregues.
La gran campanya de phishing de 2025: el compromís de "Qix"
L'incident amb el que hem començat aquest article. El 8 de setembre de 2025 es va desencadenar un dels majors incidents de la història de npm. L'atac va començar quan Josh Junon (conegut com "Qix"), mantenidor prolífic de chalk, debug, ansi-styles, strip-ansi, color-convert i una quinzena més de paquets fonamentals, va rebre un correu de phishing des de l'adreça support@npmjs.help, el domini npmjs[.]help havia estat registrat només tres dies abans, el 5 de setembre de 2025. El correu advertia que el seu compte es bloquejaria si no actualitzava les credencials 2FA abans del 10 de setembre. Junon, en el que va descriure com "un matí de pànic" i des del mòbil, va clicar l'enllaç i va introduir usuari, contrasenya i codi TOTP en una pàgina de login falsa. En qüestió de minuts, anàlisis forenses posteriors ho xifren en aproximadament 16 minuts des del compromís del compte, els atacants van començar a publicar versions malicioses. Els 18 paquets afectats sumen més de 2.000 milions de descàrregues setmanals (algunes fonts van elevar la xifra a ~2.600 milions incloent paquets relacionats). El paquet debug sol té més de 357 milions de descàrregues setmanals; ansi-styles, uns 371 milions.
La càrrega maliciosa era un lladre de criptomonedes: quan s'executava al navegador, vigilava les operacions amb carteres i, en el moment de pagar, substituïa discretament l'adreça de destinació per una de l'atacant. L'usuari veia una transacció normal; els diners anaven a una altra banda.
Com a dany col·lateral el malware va provocar fallades de build en entorns Node.js, cosa que va donar un senyal precoç als defensors, i va activar contramesures que de no haver-se produït els errors potser haguessin trigat més a arribar i els danys haguessin estat molt majors. Les versions malicioses van estar actives unes dues hores abans de ser retirades. Vercel va identificar 70 equips seus amb builds que contenien les versions compromeses en 76 projectes.
El botí econòmic va ser sorprenentment petit. Malgrat l'abast massiu, el guany real va ser mínim: Aikido (l'investigador Charlie Eriksen) va rastrejar uns 970 dòlars en fons robats, JFrog i Sygnia van estimar uns 500 dòlars, i algunes anàlisis inicials (Security Alliance) van parlar de menys de 50 dòlars. Aquesta desproporció entre abast (milers de milions de descàrregues) i dany (centenars de dòlars) és una de les lliçons més importants de l'incident: el sistema va aguantar gràcies a la resposta ràpida de la comunitat i del propi mantenidor, no pas gràcies a defenses estructurals. Eriksen va estimar que les versions malicioses es van descarregar 2,6 milions de vegades abans de ser retirades.
Nx / "s1ngularity" (agost de 2025): un dels primers casos documentats d'arma que utilitza la IA
El 26 d'agost de 2025 (cap a les 22:32 UTC), el sistema de build Nx (~4 milions de descàrregues setmanals) va ser compromès. La causa arrel va ser un flux de treball de GitHub Actions defectuós afegit el 21 d'agost que utilitzava el trigger pull_request_target amb injecció de codi via el títol d'una pull request. L'script de postinstall injectat al codi robava claus SSH, tokens de GitHub i npm, i carteres de criptomonedes.
En aquest cas la novetat alarmant va ser el primer cas documentat en què el malware va instrumentalitzar eines d'IA de línia de comandes (Claude, Gemini, Amazon Q) amb flags perillosos (--dangerously-skip-permissions, --yolo, --trust-all-tools) per fer reconeixement del sistema de fitxers. Segons The Hacker News, l'atac va filtrar 2.349 credencials. En una segona onada (28 d'agost), els atacants van fer públics repositoris privats reanomenant-los amb el prefix s1ngularity-repository.
Shai-Hulud (setembre de 2025): el primer cuc autopropagant
Detectat el 15 de setembre de 2025, Shai-Hulud (batejat com el cuc de sorra de Dune) és un dels primers cucs coneguts que opera dins la cadena de subministrament de codi obert a escala. El seu flux de treball utilitza tokens npm robats per publicar automàticament versions malicioses de tots els paquets als quals el compte compromès té accés; roba credencials (tokens de GitHub, claus de núvol d'AWS/GCP/Azure) amb eines com TruffleHog; publica jobs de GitHub Actions que exfiltren secrets; i migra repositoris privats a públics amb la descripció "Shai-Hulud Migration".
Entre els paquets populars afectats hi havia @ctrl/tinycolor (2,2 milions de descàrregues setmanals), ngx-bootstrap (300.000) i ng2-file-upload (100.000). La CISA va emetre una alerta el 23 de setembre de 2025 confirmant més de 500 paquets compromesos. Palo Alto Unit 42 va avaluar amb "confiança moderada" que un LLM es va utilitzar per generar l'script bash maliciós (basant-se en la presència de comentaris i emojis).
Una segona onada, "Shai-Hulud 2.0" (també conegut com a "sha1-hulud"), va aparèixer després amb més agressivitat: va afectar més de 25.000 repositoris, va executar-se durant la fase preinstall (abans que la majoria de defenses s'activessin) i, quan no trobava credencials vàlides, es tornava destructiu i corrompia fitxers locals. Microsoft Threat Intelligence va documentar una variant "Mini Shai-Hulud" (que va anomenar "ChainDrop") que va afectar més de 400 paquets, incloent-hi keyv, flat-cache i cache-manager.
axios (març de 2026)
El 31 de març de 2026, un compte de mantenidor compromès va convertir axios —una de les biblioteques JavaScript més usades del món, amb prop de 100 milions de descàrregues setmanals i més de 174.000 paquets dependents— en un sistema de distribució de malware durant unes tres hores, lliurant un troià d'accés remot multiplataforma.
La magnitud de la tragèdia
Sonatype, en el seu informe de programari maliciós de codi obert de 2024 (publicat el 10 de desembre de 2024), va xifrar en més de 778.500 (concretament 778.529) els paquets maliciosos acumulats des que va començar a rastrejar-los el 2019, amb un increment del 156% de 2023 a 2024. npm representa el 98,5% d'aquests (més de 540.000), enfront de l'1% (~5.000) de PyPI.
El 2025, les xifres van continuar creixent: Sonatype va comptar més de 454.600 nous paquets maliciosos, superant els 1,2 milions acumulats (un salt del 75% interanual). FortiGuard Labs va escanejar més d'1,4 milions de paquets npm i 400.000 de PyPI només al segon trimestre de 2025.
De com infectar sense credencials o accés a repositoris oficials
Aquests atacs detallats anteriorment tenen diferents vectors d'entrada, que van des de credencials reciclades de filtracions que no tenen directament a veure amb comptes npm, a sofisticats enganys de Phishing.
Però hi ha tota una línia d'atacs de compromís de paquets npm que utilitza tècniques que no requereixen d'accés als comptes oficials dels mantenidors de paquets, i que tot i això iguala el resultat letal dels atacs més intrusius.
Atacs d'error i confusió de noms i versions
- Typosquatting: noms gairebé idèntics a paquets populars, explotant errors de mecanografia (p. ex. reqeusts en lloc de requests).
- Combosquatting: afegir paraules a un nom de confiança (p. ex. noblox.js-async, noblox.js-api per imitar noblox.js).
- Brandjacking: usurpar la reputació d'una marca amb noms que s'hi assemblen molt.
- Starjacking: inflar artificialment l'aparent popularitat enllaçant el paquet maliciós al repositori de GitHub d'un projecte legítim.
Dependency confusion (o substitution attack). El febrer de 2021, Alex Birsan va publicar una investigació que va redefinir la comprensió empresarial del risc de la cadena de subministrament. Va descobrir que si registrava, en registres públics (npm, PyPI, RubyGems), paquets amb els mateixos noms que els paquets interns privats de grans empreses —noms trobats en fitxers JavaScript filtrats, manifestos i missatges d'error— amb números de versió inflats, els sistemes de build resolien i baixaven automàticament la seva versió pública en lloc de la privada.
El resultat: execució de codi confirmada dins els entorns d'Apple, Microsoft, PayPal, Shopify, Netflix, Tesla, Uber i més de 30 empreses més, sense phishing ni explotació de cap CVE. En 72 hores es van observar més de 300 paquets imitadors inundar npm. Un usuari anònim va contaminar npm i PyPI amb més de 5.000 paquets com a prova de concepte.
Slopsquatting: quan la IA inventa el nom i l'atacant el registra
L'origen del terme. "Slopsquatting" combina "AI slop" (sortida de baixa qualitat de la IA) amb "squatting". El terme va ser encunyat per Seth Larson, Security Developer-in-Residence de la Python Software Foundation.
L'estudi fundacional. El treball "We Have a Package for You! A Comprehensive Analysis of Package Hallucinations by Code Generating LLMs" (Spracklen, Wijewickrama, Sakib, Maiti, Viswanath i Jadliwala), presentat a USENIX Security 2025 (13-15 d'agost de 2025, Seattle) per investigadors de la Universitat de Texas a San Antonio, la Universitat d'Oklahoma i Virginia Tech, va analitzar 16 models generadors de codi comercials i de codi obert. Van generar 576.000 mostres de codi (2,23 milions de referències a paquets) en Python i JavaScript.
Troballes clau:
- El 19,7% dels paquets recomanats no existien: 440.445 sortides amb almenys una al·lucinació, incloent-hi 205.474 noms únics de paquets inventats.
- Els models de codi obert al·lucinaven a una taxa molt superior (21,7%) als comercials (5,2%). GPT-4 Turbo tenia la taxa més baixa (~3,59%); els models CodeLlama (7B i 34B), la més alta (fins a >33%).
- La persistència és el factor crític: en re-executar prompts idèntics 10 vegades, el 43% dels noms al·lucinats reapareixien a cada execució i el 58% en més d'una. Això fa que siguin objectius "cultivables": l'atacant només ha d'observar el model, recollir els noms que es repeteixen i registrar-los.
- Taxonomia dels noms: ~38% eren "conflacions" (mescla de dos noms reals, p. ex. express-mongoose), 13% variants tipogràfiques, 51% fabricacions pures. Els autors emmarquen el fenomen com "un repte persistent i sistèmic que mereix l'atenció urgent de la comunitat investigadora", és a dir, més com una superfície d'atac demostrada que com una explotació documentada a gran escala, però que tot i així suposa un risc molt elevat.
Tot i que no hi ha estudis concloents sobre com el conegut com el «vibe coding» (terme encunyat per Andrej Karpathy cofundador d'OpenAI, exdirector d'IA de Tesla), està potenciant el compromís de la cadena de subministrament, si que sembla clar que la pèrdua de control sobre la gestió de dependències associades a un programa no és el millor camí per a redreçar la situació. Val a dir també que l'estructura de paquets npm no té la ciberseguretat al centre per disseny, i això facilita molt aquest escenari de caos i descontrol: els arbres de dependències transitives inabastables, els scripts postinstall/preinstall que executen codi arbitrari automàticament en instal·lar, la fragilitat del sistema de manteniment de paquets, o la poca supervisió sobre el sistema de publicació generen l'ecosistema perfecte per repartir alegria a tot tipus de víctimes.
Tot i això cal destacar que hi ha maneres efectives de reduir notablement la superfície d'atac.
Recomanacions per a protegir-se
Accions immediates
- Fixa i verifica dependències. Usa lockfiles i instal·la amb
npm ci(que respecta el fitxer de bloqueig i els hashes d'integritat) en lloc denpm install. Fixa versions exactes en lloc de rangs (^,~). - Desactiva els scripts d'instal·lació per defecte:
npm install --ignore-scripts, i activa'ls només per als paquets que ho necessitin de manera conscient. - Verifica QUALSEVOL paquet que t'hagi suggerit un LLM abans d'instal·lar-lo. Comprova que existeix, qui el va registrar i quan. Un "plugin d'eslint" sense informació de mantenidor i registrat la setmana passada és una bandera vermella, independentment del recompte de descàrregues (que pot ser inflat per bots o starjacking).
- Adopta 2FA resistent al phishing: passkeys/WebAuthn en lloc de TOTP, que és susceptible d'atacs adversary-in-the-middle com el que va enganxar Junon.
Accions estructurals
- Prohibeix que els agents d'IA instal·lin paquets sense revisió humana o una allowlist, aplicada al CI/CD (no en un prompt). Tracta la instal·lació autònoma de paquets com una operació privilegiada.
- Desplega eines SCA/escaneig de dependències: Socket, Snyk, Dependabot, OSV-Scanner. Combina l'escaneig reactiu (CVE conegudes) amb la detecció proactiva (anàlisi de comportament).
- Usa un registre privat/proxy amb quarantena que retingui paquets nous durant un període de "cooldown" (p. ex. 24 hores) per evitar baixar versions malicioses durant la finestra crítica abans de la detecció i retirada.
- Migra a publicació de confiança (Trusted Publishing) amb OIDC per als fluxos de CI/CD. Una mesura que elimina els tokens de llarga durada, reduint la possibilitat que et robin aquest secret.
- Verifica l'origen. Exigeix proves criptogràfiques que acreditin d'on ve el paquet i que no s'ha manipulat pel camí quan estiguin disponibles (els estàndards habituals són SLSA i Sigstore). Comprova els camps
_npmUseritrustedPublisherals metadades del paquet.
Fonts
- blog de npm sobre event-stream — https://blog.npmjs.org
- post-mortem d'ESLint — https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes/
- Spracklen et al., "We Have a Package for You!", USENIX Security 2025 — https://usenix.org/conference/usenixsecurity25/presentation/spracklen
- Lasso Security — lasso.security/blog/ai-package-hallucinations
- Sygnia, "16 Minutes to Impact" — https://www.sygnia.co/threat-reports-and-advisories/npm-supply-chain-attack-september-2025/
- JFrog, "New compromised packages identified in largest npm attack in history" — https://jfrog.com/blog/new-compromised-packages-in-largest-npm-attack-in-history/
- The Hacker News, "20 Popular npm Packages With 2 Billion Weekly Downloads Compromised" — https://thehackernews.com/2025/09/20-popular-npm-packages-with-2-billion.html
- BankInfoSecurity, "Hackers Compromise 18 NPM Packages" — https://www.bankinfosecurity.com/hackers-compromise-18-npm-packages-in-supply-chain-attack-a-29396
- Rekt, "The Great npm Heist That Wasn't" (útil per a la desproporció abast/dany) — https://rekt.news/npm-heist
- Cyber Kendra — https://www.cyberkendra.com/2025/09/npm-packages-supply-chain-attack.html
- FortiGuard Labs, "Malicious Packages Across Open-Source Registries (Q2 2025)" — https://www.fortinet.com/blog/threat-research/malicious-packages-across-open-source-registries
- Dmitry Protsenko, "Malware Packages in NPM and PyPI: Typosquatting Guide" — https://protsenko.dev/2025/04/21/malicious-packages-in-npm-and-pypi-how-typosquatting-threatens-developers/
- Aikido, "Slopsquatting: The AI Package Hallucination Attack Already Happening" — https://www.aikido.dev/blog/slopsquatting-ai-package-hallucination-attacks