Le 12 mai 2026, Mistral AI a confirmé une intrusion. Le groupe TeamPCP revendique l'exfiltration d'environ 5 Go de code interne, répartis sur près de 450 dépôts privés. Vecteur d'entrée annoncé par l'attaquant et reconnu par Mistral : une contamination temporaire de packages publiés via la chaîne TanStack, une bibliothèque JS populaire utilisée côté front. Quelques heures de packages SDK compromis ont suffi.
C'est exactement le type d'incident que tout le monde voit venir depuis SolarWinds, et que personne n'arrête vraiment. Pas une faille zero-day exotique, pas un APT bien financé. Une lib front. Une publication malicieuse. Une fenêtre de quelques heures.
Ce qui s'est passé, mécaniquement
Le scénario raconté correspond à un schéma classique de supply chain dependency confusion / malicious publish :
- Un mainteneur d'une dépendance utilisée par Mistral est compromis (credentials NPM, token leaké, hijack de compte).
- Une version contenant du code malveillant est publiée sur le registre public.
- Les pipelines de build de Mistral résolvent automatiquement la nouvelle version (semver ou caret).
- Le code malveillant s'exécute à l'install (
postinstall) ou au runtime dans un environnement qui a accès à des tokens GitHub à scope large. - Les tokens servent à cloner les dépôts privés.
Aucun de ces maillons n'est exotique. Chacun existait dans 90% des stacks JS modernes en mai 2026.
Les trois trous à corriger en priorité
1. Le scope des tokens GitHub utilisés en CI
Beaucoup d'équipes utilisent encore un PAT (Personal Access Token) à scope repo complet pour l'organisation. Un seul de ces tokens dans un container de build, c'est l'accès à tous les dépôts privés. La bonne pratique en 2026 :
- Fine-grained PAT ou GitHub App avec accès limité aux dépôts strictement nécessaires.
- OIDC fédéré entre le runner et le cloud cible, sans long-lived secret.
- Rotation automatique tous les 7 à 30 jours.
Si vous ne savez pas répondre à "quel token tourne dans tel job et à quoi il a accès" en moins de cinq minutes, le scope est trop large.
2. La résolution semver "automatique"
Une dépendance déclarée "^1.2.3" accepte n'importe quelle version 1.x.y publiée depuis. C'est confortable pour les correctifs, c'est aussi le mécanisme exact qui a poussé le package compromis dans le build de Mistral. Trois leviers :
- Lockfile committé et respecté en CI (
npm ci,pnpm install --frozen-lockfile,yarn install --immutable). - Pinning strict des dépendances critiques (versions exactes, hash si possible).
- Délai de quarantaine sur les versions publiées récemment : un proxy interne (Verdaccio, JFrog, Sonatype) qui refuse de servir une release de moins de 48-72h. Ça bloque la majorité des typosquatting et publishes malicieux.
3. L'isolation des postinstall
Le hook postinstall de npm exécute du code arbitraire au moment du install. Dans un container de CI qui a accès au filesystem, au réseau et aux variables d'environnement, c'est une porte ouverte. Pistes :
--ignore-scriptspar défaut, allowlist explicite des packages autorisés à scripter.- Containers de build sans accès réseau sortant, sauf vers le registre interne.
- Secrets injectés au runtime de l'application, pas au build.
Ce que l'attaquant a réellement obtenu
D'après ce qui a fuité : code lié au customer management, aux abonnements API, aux calculs de coûts, aux métriques de facturation, à l'export de données. Ce n'est pas le modèle qui a fuité. C'est l'infra produit autour. La distinction est importante pour comprendre l'impact :
- Modèle (poids, dataset, archi d'entraînement) : valeur stratégique brute, mais difficile à exploiter sans capacité GPU massive.
- Infra produit (auth, billing, API keys management) : valeur opérationnelle immédiate. Permet à un attaquant de comprendre la surface d'attaque, de trouver des secrets oubliés, de modéliser les futurs accès.
Le second a beaucoup plus de valeur pour quelqu'un qui veut reposter sur Mistral plus tard. Et c'est aussi ce qui a le plus de valeur pour un concurrent qui veut comprendre comment vous gagnez votre argent.
Le SBOM ne vous aurait pas sauvé seul
Beaucoup de réactions à l'incident ont pointé vers le SBOM comme remède. Le SBOM, SPDX ou CycloneDX, liste vos dépendances avec leur version. C'est nécessaire pour la conformité (CRA, secteur public) et pour répondre vite à un CVE connu. Mais face à un package légitime qui devient malicieux entre deux versions, le SBOM seul n'arrête rien : il vous dit quoi, pas quoi de neuf et de suspect.
Le combo qui marche en pratique :
- SBOM généré et signé à chaque build.
- Proxy interne avec quarantaine sur les nouvelles versions.
- Scan SCA continu (Snyk, Trivy, Dependency-Track) qui matche le SBOM avec les advisories en temps réel.
- Lockfile audité dans la review PR (au moins pour les dépendances ajoutées).
Ce que je conseille de faire cette semaine
Si vous êtes éditeur, IA ou non, et que votre stack est JS/TS :
- Lister les tokens en CI qui ont accès à plus d'un dépôt et réduire le scope.
- Vérifier que tous les pipelines de build utilisent
npm ciou équivalent immutable. - Mettre
--ignore-scriptspar défaut, allowlister manuellement. - Activer la quarantaine sur le registre interne si vous en avez un. Si vous n'en avez pas, c'est probablement le moment.
- Auditer les dépendances ajoutées dans les 30 derniers jours : qui les maintient, depuis combien de temps, quel volume de téléchargements.
Pour la lecture de l'angle souveraineté du même incident, voir Mistral et la fragilité de la souveraineté EU. Pour la gestion d'une demande de rançon comme celle reçue par Mistral, Réponse à incident et rançon : la décision $25k.