+− THE DAILY DIFFdev & AI news
SHIP IT

Une mise à jour Dependabot a publié un ver. 22 paquets.

Un bot ouvre une pull request.

Un bot ouvre une pull request. Un humain la fusionne 24 minutes plus tard. 95 minutes après, un ver a publié 110 versions malveillantes de ses 22 paquets npm, sous son nom, avec un jeton qu'il a trouvé dans son CI.

Lire l'édition écrite (anglais) ↗

Ce que cette vidéo couvre

  • Un bot, un humain, un ver
  • Comment c'est arrivé, pourquoi npm l'a permis, qui est à blâmer
  • Chronologie : le cache empoisonné
  • 21:48 — la mise à jour Dependabot
  • Pourquoi ça marche

Transcription traduite

Traduit de la narration originale en anglais. L'audio et les sous-titres disponibles sont contrôlés par YouTube.

Un bot, un humain, un ver

0:00 Un bot ouvre une pull request ; un humain la fusionne vingt-quatre minutes plus tard. Quatre-vingt-quinze minutes plus tard, un ver a publié cent dix versions de ses paquets, en se faisant passer pour lui. Le postmortem de TanStack contient les horodatages en amont, celui du mainteneur en aval contient le reste, et Hacker News lui donne mille cent points et un nom : Mini Shai-Hulud. Comment ça arrive, pourquoi npm le permet, qui est à blâmer.

Comment c'est arrivé, pourquoi npm l'a permis, qui est à blâmer

0:21 Voici The Daily Diff, postmortem. 11 mai, matin. Un fork renommé ouvre une pull request contre TanStack Router. Elle se ferme dans l'heure, mais un workflow de benchmark a déjà exécuté son code et

Chronologie : le cache empoisonné

0:33 enregistré un cache empoisonné sous la clé que le workflow de release utilisera. Dix-neuf-vingt. Une fusion légitime exécute la release. Le cache revient, un binaire lit la mémoire du runner, dérobe le jeton de publication, et publie quatre-vingt-quatre versions sur quarante-deux paquets, avec une provenance valide. Les tests échouent. Il publie quand même. Dix-neuf quarante-six, un chercheur de StepSecurity dépose le problème ; à neuf UTC tout est déprécié et l'avis est publié.

0:55 Déprécié ne veut pas dire disparu : npm refuse de désinstaller quoi que ce soit avec des dépendants, donc ça reste installable pendant des heures. Vingt-et-un quarante-huit. Dans un projet de données aéronautiques à neuf étoiles, Dependabot ouvre sa pull request de routine : mettre à jour le groupe de dev-dépendances, treize mises à jour. Deux sont des versions empoisonnées de TanStack. Vingt-deux-douze : fusionné. Le workflow de publication exécute npm C-I avec le jeton en

21:48 — la mise à jour Dependabot

1:15 portée ; un script de préparation le lit, et à vingt-deux-dix-sept le ver publie sous son nom. Cinq versions de chaque paquet que le jeton atteint, même un ancien projet secondaire : un jeton classique pour tout. Cent dix versions en quatre-vingt-quinze minutes. Il le découvre par e-mail, après minuit. Pourquoi ça marche. Un : npm install exécute les scripts de cycle de vie d'inconnus par défaut, et le script de préparation d'une dépendance git compte.

1:39 Deux : le ver veut une chose : un jeton qui publie sans deuxième facteur. Ensuite, il demande au registre ce que ce mainteneur possède d'autre, et republie tout avec lui-même à l'intérieur. Trois : rien dans la chaîne n'est une personne.

Pourquoi ça marche

1:51 Un bot propose, un pipeline installe, et le ver rend la pareille : ses branches mortes sont nommées dependabot slash github-actions slash fremen. git blame. Le modèle d'installation de npm, cinquante-cinq pour cent : les scripts s'exécutent à l'installation, le déprécié reste installable, des jetons de contournement à deux facteurs existent. Le CI de TanStack, vingt-cinq : un workflow cible de pull request non audité exécutant du code de fork avec un accès en écriture au cache. L'habitude de la mise à jour, quinze : treize mises à jour fusionnées en vingt-quatre minutes, jeton dans la pièce.

2:17 Dependabot, cinq : si fiable que le ver porte son uniforme.

git blame

2:20 Rayon d'action : quarante-deux paquets TanStack. Vingt-deux en aval, à partir d'un projet avec neuf étoiles. Plus de cent soixante à l'échelle de l'écosystème une fois que le ver atteint Mistral. Chaque version en amont portait une signature valide : construite par le pipeline officiel. Vrai. Verdict, postmortem : SHIP IT. Les deux mainteneurs publient des postmortems horodatés dans la journée ; dans les trois, le pipeline en aval s'installe avec ignore-scripts, sépare la construction de la publication, et supprime le jeton de longue durée.

Rayon d'action

2:47 Les paramètres par défaut de npm n'ont pas bougé. Lundi : ignore-scripts à l'installation, et le jeton de publication hors du job qui l'exécute. Envoyez-moi l'incident dont vous n'êtes toujours pas autorisé à parler, dans les commentaires, ou à thedailydiff.dev. Et c'est le diff pour aujourd'hui.

Verdict

3:00 Je suis Niko d'Axrisi. Fusionnez de manière responsable.

Sources

  1. TanStack postmortem (Tanner Linsley, May 11, refined May 15)tanstack.com
  2. TanStack "Hardening TanStack After the npm Compromise" (May 12)tanstack.com
  3. TanStack/router#7383 — the StepSecurity detection issuegithub.com
  4. Downstream incident post, @squawk/* (May 12)github.com
  5. Downstream hardening post (May 14)github.com
  6. The Dependabot PR #246 (opened 21:48 UTC, merged 22:12)github.com
  7. @tan_stack advisory post, 21:19 UTCx.com
  8. StepSecurity — worm internals, bypass_2fa search, Dependabot-style branch nameswww.stepsecurity.io
  9. Socketsocket.dev
  10. Aikido — "over 160 packages, including Mistral"www.aikido.dev
  11. Hacker News (1,097 points)news.ycombinator.com

Vidéos similaires