D-OPEN

Comment securiser votre pipeline npm contre les attaques supply chain en 7 etapes — guide pratique pour developpeurs open source

Securiser pipeline npm supply chain developpeurs open source
Thomas Eriksen

Thomas Eriksen

Developpeur DevSecOps et mainteneur open source · 15 mai 2026 · 12 min de lecture

TL;DR

  • • L attaque Mini Shai-Hulud (mai 2026) a compromis 169 paquets npm dont TanStack via les pipelines CI/CD. Ce guide detaille 7 etapes concretes pour securiser votre pipeline npm contre ce type d attaque.
  • • Les mesures essentielles : lockfiles stricts avec npm ci, audit automatise en CI, securisation de pull_request_target, publication OIDC avec contraintes, caching isole, et monitoring des publications.
  • • Chaque etape inclut des exemples de code prets a copier-coller dans vos projets. Applicable immediatement, quel que soit la taille de votre projet open source.

L attaque Mini Shai-Hulud du 11 mai 2026 a compromis 169 paquets npm et PyPI, dont 42 paquets @tanstack/* totalisant 518 millions de telechargements cumulatifs. L attaque a exploite des faiblesses dans les workflows GitHub Actions — pas dans le code des paquets eux-memes. Le CVE-2026-45321 (CVSS 9.6) a demontre que meme les projets les mieux maintenus sont vulnerables si leurs pipelines CI/CD ne sont pas securises. Ce guide vous donne les 7 etapes concretes, avec des exemples de code prets a l emploi, pour proteger votre pipeline npm contre ce type d attaque. Que vous mainteniez un petit projet personnel ou une bibliotheque utilisee par des milliers de developpeurs, ces etapes s appliquent a vous. Pour une analyse complete de l attaque elle-meme, consultez notre article sur Mini Shai-Hulud et la compromission de TanStack.

💡 Notre avis d expert

La securite supply chain npm n est plus optionnelle en 2026. Avec Mini Shai-Hulud, LiteLLM, et les attaques de typosquatting qui se multiplient, chaque projet npm est une cible potentielle. La bonne nouvelle : 90% des attaques peuvent etre prevenues avec les 7 mesures de ce guide. La mauvaise nouvelle : la majorite des projets open source n en appliquent aucune. Si vous lisez cet article, vous etes deja en avance sur la courbe.

7 ETAPES POUR SECURISER VOTRE PIPELINE NPM1Lockfilesstricts+ npm ci2Audit autonpm auditen CI/CD3GitHubActionssecurises4PublicationOIDCcontrainte5Cachingisole etsecurise6DependabotRenovateconfigure7Monitoringtemps reelalertesCOUVERTURE DES VECTEURS D ATTAQUEPaquets malveillantsEtapes 1, 2, 6Compromission CI/CDEtapes 3, 4, 5Detection post-attaqueEtapes 2, 7Ces 7 etapes auraient prevenu l attaque Mini Shai-Hulud

Etape 1 : Verrouillez vos dependances avec des lockfiles stricts

Le lockfile est votre premiere ligne de defense contre les attaques supply chain. Un lockfile correctement configure garantit que chaque installation reproduit exactement les memes versions de dependances — pas une version plus recente qui pourrait etre compromise. Le probleme est que beaucoup de developpeurs traitent le lockfile comme un fichier technique a ignorer, et certains vont meme jusqu a l ajouter dans .gitignore. C est une erreur critique.

La regle fondamentale : en CI/CD et en production, utilisez toujours npm ci au lieu de npm install. La difference est cruciale : npm ci installe les dependances exactement telles que specifiees dans le lockfile, sans le modifier. Si une dependance dans le lockfile ne correspond pas a package.json, la commande echoue au lieu de resoudre silencieusement. npm install, en revanche, peut mettre a jour le lockfile pour inclure des versions plus recentes — ce qui, dans le cas de Mini Shai-Hulud, aurait pu tirer automatiquement les versions compromises.

# .npmrc — a placer a la racine de votre projet
# Empeche npm install de modifier le lockfile
package-lock=true
save-exact=true

# Pour pnpm, ajoutez dans .npmrc :
# frozen-lockfile=true

# En CI/CD, utilisez TOUJOURS npm ci :
# npm ci --ignore-scripts  # si les scripts postinstall ne sont pas necessaires
# npm ci                    # si les scripts postinstall sont necessaires

# Verifiez l integrite du lockfile avant chaque build :
npm ci --audit=false && npm audit --production

Configurez egalement save-exact=true dans votre .npmrc pour que chaque npm install en local enregistre les versions exactes (par exemple 1.2.3) au lieu de ranges (comme ^1.2.3). Les ranges sont la premiere cause d installation accidentelle de versions non prevues. Pour les projets utilisant pnpm, activez frozen-lockfile=true qui offre une protection equivalente a npm ci.

Etape 2 : Configurez un audit automatise dans votre CI/CD

L audit manuel est insuffisant. Vous ne pouvez pas vous rappeler de lancer npm audit avant chaque deploiement, et les vulnerabilites sont decouvertes en continu. L audit doit etre automatise et bloquant : chaque build CI/CD doit inclure un audit qui fait echouer le pipeline si des vulnerabilites critiques sont detectees. Voici un workflow GitHub Actions complet que vous pouvez copier dans votre projet.

# .github/workflows/security-audit.yml
name: Security Audit
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  schedule:
    - cron: '0 8 * * 1'  # Chaque lundi a 8h UTC

jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install dependencies (locked)
        run: npm ci

      - name: Run npm audit
        run: npm audit --audit-level=high --production
        # Echoue si vulnerabilites HIGH ou CRITICAL

      - name: Verify package signatures
        run: npm audit signatures
        # Verifie les signatures OIDC des paquets

      - name: Check for known malicious packages
        run: npx is-my-node-vulnerable
        # Verifie Node.js lui-meme

Le parametre --audit-level=high est un equilibre pragmatique : il bloque le pipeline pour les vulnerabilites HIGH et CRITICAL tout en laissant passer les LOW et MODERATE qui sont souvent des faux positifs ou des vulnerabilites theoriques sans impact reel. Pour les projets critiques (applications financieres, sante, infrastructure), utilisez --audit-level=moderate. Le schedule hebdomadaire (cron: '0 8 * * 1') attrape les vulnerabilites qui sont decouvertes entre les depliegments — comme Mini Shai-Hulud qui a ete identifie apres la publication. Pour aller plus loin, consultez notre guide complet sur l integration d un scanner de vulnerabilites IA dans votre pipeline CI/CD.

Etape 3 : Securisez vos workflows GitHub Actions

C est l etape qui aurait directement prevenu l attaque Mini Shai-Hulud. Le coeur du probleme est l utilisation de pull_request_target combine avec un checkout du code du fork. Voici les regles strictes a appliquer a tous vos workflows.

Regle 1 : N utilisez JAMAIS pull_request_target pour les builds et les tests. Utilisez pull_request a la place. L evenement pull_request execute le workflow dans le contexte du fork avec des permissions en lecture seule et sans acces aux secrets. C est exactement ce dont vous avez besoin pour builder et tester le code d un contributeur externe.

Regle 2 : Si pull_request_target est necessaire, ne faites JAMAIS un checkout du code du fork. Certains cas d usage legitimes existent : ajouter un label a une PR, poster un commentaire de bienvenue, verifier un CLA. Pour ces cas, le workflow doit utiliser uniquement le code du repository de base et les metadonnees de la PR (titre, auteur, labels) — jamais le contenu du code de la PR elle-meme.

# .github/workflows/pr-build.yml — SECURISE
name: PR Build & Test
on:
  pull_request:  # PAS pull_request_target
    branches: [main]

permissions:
  contents: read  # Permissions minimales

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        # Checkout du code du fork — lecture seule, pas de secrets

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm ci
      - run: npm test
      - run: npm run build

---

# .github/workflows/pr-label.yml — Si pull_request_target est NECESSAIRE
name: PR Auto Label
on:
  pull_request_target:
    types: [opened]

permissions:
  pull-requests: write  # Seulement ce qui est necessaire

jobs:
  label:
    runs-on: ubuntu-latest
    steps:
      # PAS de actions/checkout — on n execute PAS le code du fork
      - uses: actions/labeler@v5
        with:
          repo-token: "${{ secrets.GITHUB_TOKEN }}"

Regle 3 : Appliquez le principe du moindre privilege. Chaque workflow doit declarer explicitement ses permissions au niveau minimum necessaire. Un workflow de test n a besoin que de contents: read. Un workflow de publication n a besoin que de contents: read et id-token: write. N utilisez jamais les permissions par defaut qui accordent un acces en ecriture generalise. Notre guide pour auditer les runners GitHub Actions couvre ces patterns en profondeur, y compris la gestion des runners self-hosted.

💡 Notre avis d expert

Le pattern le plus dangereux que nous voyons dans les projets open source francais est un workflow unique qui fait tout : build, test, publication, labeling. Ce workflow a necessairement des permissions elevees (pour publier) et est declenche par des PRs (pour tester). C est exactement le scenario ou pull_request_target + checkout du fork devient mortel. Separez vos workflows : un pour les PRs (pull_request, permissions minimales), un pour la publication (push sur main ou tag, permissions de publication). Jamais les deux dans le meme fichier.

Etape 4 : Configurez la publication OIDC avec des contraintes strictes

La publication via OIDC (OpenID Connect) est meilleure que les tokens npm classiques — les tokens OIDC sont ephemeres et lies a un workflow specifique, contrairement aux tokens npm qui sont permanents et peuvent etre voles. Mais comme Mini Shai-Hulud l a demontre, OIDC seul ne suffit pas si le workflow qui genere le token OIDC peut etre compromis. La solution est d ajouter des contraintes strictes sur les conditions de publication.

# .github/workflows/publish.yml — Publication securisee
name: Publish to npm
on:
  push:
    tags:
      - 'v*'  # Declenche UNIQUEMENT sur les tags de version

permissions:
  contents: read
  id-token: write  # Necessaire pour OIDC

jobs:
  publish:
    runs-on: ubuntu-latest
    # IMPORTANT: environnement avec approbation requise
    environment: npm-publish
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.ref }}
          # Checkout du tag — PAS d une PR

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          registry-url: 'https://registry.npmjs.org'

      - run: npm ci
      - run: npm test
      - run: npm run build

      - run: npm publish --provenance --access public
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
          # Ou avec OIDC pur (sans NPM_TOKEN) :
          # npm publish --provenance --access public

Les trois protections cles dans ce workflow : 1) Le workflow est declenche uniquement par des tags de version (push: tags: ['v*']), pas par des PRs. Un attaquant ne peut pas declencher une publication en soumettant une PR. 2) L environnement npm-publish exige une approbation manuelle avant de s executer — configurez cela dans les parametres du repository sous Environments. Meme si un attaquant parvient a pousser un tag, il doit encore obtenir l approbation d un mainteneur. 3) Le flag --provenance genere une attestation de provenance verifiable qui lie le paquet au commit source et au workflow exact qui l a produit.

Etape 5 : Isolez vos caches CI/CD

L empoisonnement du cache est le vecteur d attaque qui a permis a Mini Shai-Hulud de passer de "code malveillant execute dans un workflow" a "paquets malveillants publies". L attaquant a modifie le store pnpm dans le cache GitHub Actions, et ce cache empoisonne a ete restaure lors du prochain build legitime. La solution est d isoler les caches entre les workflows de PRs et les workflows de publication.

# Cache SECURISE — cle incluant le SHA pour eviter la reutilisation
- uses: actions/cache@v4
  with:
    path: |
      ~/.npm
      node_modules
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}-${{ github.sha }}
    restore-keys: |
      ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}-
    # Le SHA dans la cle empeche la reutilisation d un cache
    # empoisonne par un workflow precedent

# Pour les workflows de PUBLICATION, desactivez completement le cache :
- uses: actions/setup-node@v4
  with:
    node-version: '20'
    registry-url: 'https://registry.npmjs.org'
    # PAS de cache: 'npm' ici — clean install a chaque publication

Pour les workflows de publication, la recommandation la plus sure est de desactiver completement le cache. La penalite en temps de build (quelques minutes supplementaires pour un npm ci complet) est negligeable comparee au risque d un cache empoisonne. Pour les workflows de PR et de test, utilisez des cles de cache qui incluent le github.sha pour garantir l unicite. N oubliez pas non plus de vider regulierement vos caches en allant dans les parametres GitHub Actions de votre repo. Notre article sur la configuration d un pipeline CI/CD securise pour les projets open source couvre les strategies de cache avancees.

Besoin d aide pour securiser vos pipelines npm ?

Audit GitHub Actions, configuration OIDC, isolation des caches, mise en place de Dependabot/Renovate — notre equipe vous accompagne de A a Z.

Nous contacter

Etape 6 : Configurez Dependabot ou Renovate pour les mises a jour controlees

Les mises a jour automatiques non controlees sont un vecteur d attaque classique. Si votre CI/CD met a jour les dependances automatiquement (via npm install au lieu de npm ci), une version compromise peut etre tiree automatiquement dans votre build. Dependabot et Renovate resolvent ce probleme en creant des PRs de mise a jour que vous pouvez reviewer avant de les merger.

# .github/dependabot.yml — Configuration recommandee
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
      day: "monday"
      time: "09:00"
      timezone: "Europe/Paris"
    open-pull-requests-limit: 10
    reviewers:
      - "votre-equipe-securite"
    labels:
      - "dependencies"
      - "security"
    # Grouper les mises a jour mineures
    groups:
      minor-and-patch:
        update-types:
          - "minor"
          - "patch"
    # Bloquer les mises a jour automatiques de certains paquets critiques
    ignore:
      - dependency-name: "*"
        update-types: ["version-update:semver-major"]
        # Les mises a jour majeures necesitent une review manuelle

  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"
    # IMPORTANT: gardez vos actions GitHub a jour aussi

Deux points critiques dans cette configuration. Premierement, le reviewers assigne — chaque mise a jour de dependance doit etre verifiee par un humain avant d etre mergee. C est la couche de protection que les mises a jour automatiques contournent. Deuxiemement, le monitoring des github-actions — les actions GitHub elles-memes sont des dependances qui peuvent etre compromises. Mini Shai-Hulud a exploite des actions GitHub, pas seulement des paquets npm. Notre guide detaille sur la configuration de Dependabot et Renovate couvre les strategies avancees incluant les policies de version et les overrides de securite.

Etape 7 : Mettez en place un monitoring en temps reel

Les 6 etapes precedentes sont des mesures preventives. Le monitoring est votre filet de securite — il detecte les anomalies quand les preventions echouent. Mini Shai-Hulud a ete detecte par la communaute en environ 90 minutes. Pour un projet critique, 90 minutes de compromission peuvent etre devastatrices. Un monitoring efficace reduit cette fenetre a des minutes, voire des secondes.

Voici les signaux a surveiller et les outils pour le faire :

# Script de monitoring basique — a executer en cron
#!/bin/bash

# 1. Verifier les nouvelles versions de vos dependances critiques
CRITICAL_PACKAGES="@tanstack/react-router @tanstack/react-query"
for pkg in $CRITICAL_PACKAGES; do
  LATEST=$(npm view "$pkg" version 2>/dev/null)
  CURRENT=$(node -p "require('./node_modules/$pkg/package.json').version" 2>/dev/null)
  if [ "$LATEST" != "$CURRENT" ]; then
    echo "ALERT: $pkg a une nouvelle version: $LATEST (actuelle: $CURRENT)"
    # Envoyer une notification Slack/Discord/email
  fi
done

# 2. Verifier les signatures npm
npm audit signatures 2>&1 | grep -i "invalid" && echo "ALERT: Signatures invalides detectees"

# 3. Verifier les scripts postinstall suspects
npx -y can-i-ignore-scripts

# 4. Socket.dev pour une analyse avancee (option payante)
# npx socket report create --package-lock

Pour un monitoring plus avance, des outils comme Socket.dev et Snyk offrent une analyse en temps reel des dependances npm avec detection des comportements suspects (acces reseau inattendu, acces au systeme de fichiers, execution de scripts, etc.). Ces outils auraient potentiellement detecte le payload de Mini Shai-Hulud lors de l installation grace a leur analyse comportementale. Pour les projets open source, Socket.dev offre un tier gratuit qui couvre la plupart des besoins. Si vous publiez des paquets npm, surveillez egalement les publications non autorisees sur votre scope — configurez des alertes npm pour etre notifie de chaque nouvelle version publiee sous votre namespace.

DEFENSE EN PROFONDEUR — 7 COUCHES DE PROTECTION NPM7. MONITORING TEMPS REEL6. DEPENDABOT / RENOVATE5. CACHING ISOLE4. PUBLICATION OIDC CONTRAINTE3. GITHUB ACTIONS SECURISES2. AUDIT AUTOMATISE CI/CD1. LOCKFILES STRICTS + npm ci

💡 Notre avis d expert

Si vous ne deviez retenir que 3 choses de cet article : 1) Utilisez npm ci, jamais npm install en CI/CD. 2) Supprimez tout usage de pull_request_target avec checkout du fork. 3) Separez vos workflows de test et de publication. Ces trois mesures seules auraient prevenu Mini Shai-Hulud. Le reste est de la defense en profondeur — importante, mais ces trois regles sont non negociables.

FAQ

Pourquoi npm audit seul ne suffit-il pas pour proteger contre les attaques supply chain ?

npm audit verifie uniquement les vulnerabilites connues referencees dans la base de donnees des advisories npm. Il ne detecte pas les paquets malveillants zero-day (comme ceux de Mini Shai-Hulud avant leur identification), les paquets publies avec des identites OIDC compromises, ni les modifications subtiles dans le code des dependances. Pour une protection complete, il faut combiner npm audit avec le verrouillage strict des lockfiles, l audit des signatures, le monitoring des publications, et la securisation des workflows CI/CD. C est pourquoi ce guide comprend 7 etapes et pas seulement "lancez npm audit".

Comment configurer GitHub Actions pour eviter les attaques via pull_request_target ?

Trois regles fondamentales : 1) N utilisez jamais pull_request_target pour les workflows de build et de test — utilisez pull_request a la place, qui execute le code dans le contexte du fork avec des permissions en lecture seule. 2) Si pull_request_target est absolument necessaire (pour le labeling ou les commentaires automatiques), ne faites JAMAIS un checkout du code du fork — utilisez uniquement les metadonnees de la PR. 3) Activez les approbations requises pour les workflows des contributeurs externes dans les parametres de votre repository. Ces trois regles auraient prevenu l attaque Mini Shai-Hulud.

Quelle est la difference entre npm ci et npm install pour la securite ?

npm ci (clean install) installe les dependances exactement comme specifiees dans le lockfile, sans le modifier. Si une dependance dans le lockfile ne correspond pas a package.json, npm ci echoue au lieu de mettre a jour silencieusement. npm install, en revanche, peut modifier le lockfile pour resoudre les dependances, ce qui peut introduire des versions non prevues — y compris des versions compromises. En CI/CD et en production, utilisez toujours npm ci pour garantir des builds reproductibles. Localement, npm install reste acceptable pour ajouter de nouvelles dependances, mais commitez toujours le lockfile mis a jour apres verification.

Comment Dependabot et Renovate aident-ils a prevenir les attaques supply chain npm ?

Dependabot et Renovate creent des PRs automatisees quand de nouvelles versions de dependances sont disponibles, permettant une revue humaine avant la mise a jour. Ils peuvent etre configures pour grouper les mises a jour mineures, exiger des approbations specifiques pour les mises a jour majeures, et surveiller les advisories de securite. Combines avec un lockfile strict et npm ci en CI/CD, ils empechent les mises a jour automatiques non controlees qui pourraient introduire des paquets compromis. N oubliez pas de configurer egalement le monitoring des github-actions dans Dependabot — les actions GitHub elles-memes sont des dependances qui peuvent etre compromises.

Securisez vos pipelines npm et vos workflows CI/CD

Audit de securite complet, configuration Dependabot/Renovate, securisation GitHub Actions, mise en place OIDC, monitoring temps reel — de A a Z.

Demander un accompagnement

Articles lies :

Sources : npm audit documentation, GitHub Actions security hardening, Socket.dev