Mini Shai-Hulud frappe openapi-react-query-codegen : 10 versions malveillantes, npm provenance et pourquoi TanStack Query n’a pas été compromis Skip to content

Mini Shai-Hulud frappe openapi-react-query-codegen : 10 versions malveillantes, npm provenance et pourquoi TanStack Query n’a pas été compromis

Analyse vérifiée de l’attaque du 28 août 2026 contre @7nohe/openapi-react-query-codegen : 10 versions malveillantes, GitHub Actions issue_comment, npm Trusted Publishing, provenance valide, binding.gyp, IOCs, remédiation et distinction avec TanStack Query.

Publié Rédigé par Temps de lecture 17 min de lecture

Analyse vérifiée de l’attaque du 28 août 2026 contre @7nohe/openapi-react-query-codegen : 10 versions malveillantes, GitHub Actions issue_comment, npm Trusted Publishing, provenance valide, binding.gyp, IOCs, remédiation et distinction avec TanStack Query.

Sur cette page
  1. 1TL;DR
  2. 2Que s’est-il passé le 28 août ?
  3. 3TanStack Query lui-même n’a pas été compromis
  4. 4À quoi sert le paquet ?
  5. 5Quelle était sa popularité ?
  6. 6L’attaque a commencé dans GitHub Actions
  7. 7Un commentaire pouvait entrer dans le chemin de release
  8. 8Le checkout du fork a transformé des données en code exécuté
  9. 9id-token: write a ouvert la voie à npm
  10. 10Aucun vol de mot de passe npm n’était nécessaire
  11. 11Les releases malveillantes avaient une provenance valide
  12. 12Provenance n’est pas un scanner de malware
  13. 13Premier chemin d’exécution : binding.gyp
  14. 14Deuxième chemin : preinstall
  15. 15Les deux prereleases étaient différentes
  16. 16Payload principal : 3FWCvzduYZg.js
  17. 17Comportement runtime
  18. 18Quels secrets doivent être considérés exposés ?
  19. 19Pourquoi une dev dependency peut être critique
  20. 20Installer un package est une surface d’exécution
  21. 21TeamPCP est-il certainement responsable ?
  22. 22Pourquoi Mini Shai-Hulud revient-il ?
  23. 23L’incident TanStack de mai était différent
  24. 24Query était aussi sain en mai
  25. 25L’incident de mai a eu de vraies conséquences downstream
  26. 26Août vs mai
  27. 27Comment vérifier son exposition ?
  28. 28IOCs principaux
  29. 29Remédiation
  30. 30Quelles versions sont propres ?
  31. 31Qu’a corrigé le mainteneur ?
  32. 32Durcir GitHub Actions
  33. 33Durcir l’installation des dépendances
  34. 34Checklist de production
  35. 35Verdict POLPROG

Le 28 août 2026, le paquet npm @7nohe/openapi-react-query-codegen a été compromis. Il génère des clients TypeScript et des hooks TanStack Query à partir de schémas OpenAPI.[1][2][3]

L’attaquant n’a pas eu besoin du mot de passe npm du mainteneur ni d’un token de publication longue durée.

La faille était dans le workflow de release GitHub Actions.

Un événement :

issue_comment

pouvait lancer le chemin de publication lorsqu’un commentaire de pull request contenait exactement :

npm publish

sans contrôle suffisant du rôle de l’auteur.[1][2]

Le pipeline faisait ensuite :

checkout du code du PR
→ pnpm install
→ id-token: write
→ npm Trusted Publishing

[1][2]

Résultat : 10 versions malveillantes ont été publiées avec une provenance npm valide.[1][3]

La leçon centrale est simple :

La provenance peut prouver correctement l’origine d’un build alors que le build lui-même est malveillant.

Autre précision essentielle : @tanstack/react-query n’a pas été compromis dans cet incident. Le paquet attaqué est un générateur tiers utilisé avec TanStack Query.[6][7]

État des informations : 31 août 2026.

TL;DR

QuestionRéponse vérifiée
Paquet compromis@7nohe/openapi-react-query-codegen
Date28 août 2026
Versions malveillantes10
Versions stables malveillantes8
Prereleases malveillantes2
@tanstack/react-query compromis ?Non
Vecteur principalWorkflow GitHub Actions issue_comment mal configuré
Mot de passe mainteneur nécessaire ?Non
Long-lived npm token nécessaire ?Non
Autorité de publicationid-token: write + npm Trusted Publishing
Provenance valide ?Oui
Provenance = code sûr ?Non
Chemins d’exécutionbinding.gyp, plus preinstall pour certaines versions
Payload principal3FWCvzduYZg.js
latest actuel3.0.2
SévéritéCritical, CVSS 9.6
CVEAucun CVE connu dans l’advisory au 31 août
FamilleActivité liée/dérivée de Mini Shai-Hulud
Attribution opérateur certaine ?Non
Réponse prioritaireIsoler l’hôte et tourner les credentials depuis une machine propre

Que s’est-il passé le 28 août ?

L’advisory GitHub GHSA-9pvf-vcx3-x239 recense 10 versions malveillantes publiées entre environ 20:00 et 20:21 UTC.[1]

Versions stables :

0.5.4
0.5.5
1.6.3
1.6.4
2.2.1
2.2.2
3.0.3
3.0.4

Prereleases :

0.0.0-365d4eb738d3146583431948d3ba6e27a32556be
0.0.0-ec7876d6c917dad516ba69bbfafc948b834bf0ab

[1][2]

Le tag latest pointait vers 3.0.4 d’environ 20:19:29 UTC jusqu’à environ 22:51 UTC, puis a été rétabli sur 3.0.2.[1]

TanStack Query lui-même n’a pas été compromis

Dire « TanStack Query hacked » est incorrect.

@7nohe/openapi-react-query-codegen est un projet indépendant qui génère du code pour :

@tanstack/react-query

[6]

C’est une relation technologique, pas une appartenance au projet TanStack.

Le paquet officiel @tanstack/react-query est distinct, et le postmortem de TanStack sur l’incident de mai listait également Query parmi les familles non affectées.[7][11]

À quoi sert le paquet ?

Il génère notamment :

  • clients API typés,
  • query keys,
  • queryOptions,
  • infiniteQueryOptions,
  • useQuery,
  • useMutation,
  • helpers Suspense, prefetch et SSR.

[6]

Flux typique :

OpenAPI schema
↓
codegen
↓
TypeScript client
↓
TanStack Query hooks/options

Quelle était sa popularité ?

Le 31 août, npm affichait environ 155 000 téléchargements hebdomadaires.[6]

C’est une métrique dynamique.

Plus important : ce type de dev dependency tourne sur des machines de développeurs et des runners CI, souvent proches de secrets GitHub, SSH, cloud et deployment.

L’attaque a commencé dans GitHub Actions

Le workflow écoutait :

on:
  issue_comment:
    types: [created]

[1]

La chaîne dangereuse était :

commentaire externe
+ pas de contrôle d’autorisation
+ checkout du PR
+ exécution du code
+ id-token: write
+ publish

Un commentaire pouvait entrer dans le chemin de release

Le workflow vérifiait essentiellement que le commentaire concernait un PR et contenait exactement npm publish.[1][2]

Il manquait une vérification robuste de type :

OWNER
MEMBER
COLLABORATOR

Un compte externe pouvait donc atteindre le job privilégié.

Le checkout du fork a transformé des données en code exécuté

Le pipeline checkoutait le code du PR puis exécutait :

pnpm install

[2]

Le contenu contrôlé par l’attaquant s’exécutait alors dans un contexte privilégié.

GitHub déconseille explicitement d’exécuter du code de PR non fiable dans des workflows disposant de privilèges élevés.[9]

id-token: write a ouvert la voie à npm

Le job possédait :

permissions:
  id-token: write

[1][2]

Cette permission est légitime pour npm Trusted Publishing via OIDC.[10]

Le problème n’était pas OIDC, mais l’exécution de code non fiable dans un job autorisé à obtenir cette identité.

Aucun vol de mot de passe npm n’était nécessaire

StepSecurity souligne que l’attaquant n’avait pas besoin d’un mot de passe mainteneur ni d’un token de publication longue durée.[2]

Ancien modèle :

voler un token → publier

Nouveau modèle :

contrôler l’exécution du workflow de confiance
→ obtenir une identité légitime
→ publier

Les releases malveillantes avaient une provenance valide

Elles ont été publiées par le véritable workflow avec Trusted Publishing, donc avec des attestations de provenance valides.[1][3]

La provenance disait correctement :

cet artefact vient
de ce repo
via ce workflow

Mais elle ne disait pas que le code checkouté avait été autorisé.

Provenance n’est pas un scanner de malware

La provenance peut vérifier l’origine et la chaîne de build.

Elle ne garantit pas :

  • que le source est sain,
  • que le PR est autorisé,
  • que le workflow est sûr,
  • que l’artefact est exempt de malware.

Donc :

valid provenance ≠ safe package

[10]

Premier chemin d’exécution : binding.gyp

Certaines versions n’avaient aucun preinstall visible.[1]

Elles ajoutaient plutôt :

binding.gyp

Le mécanisme GYP/Python était détourné afin d’atteindre os.system() et lancer le JavaScript malveillant.[1][5]

Une règle de sécurité qui ne cherche que preinstall/postinstall est donc insuffisante.

Deuxième chemin : preinstall

D’autres versions stables ajoutaient :

"preinstall": "node 3FWCvzduYZg.js"

[1][2]

Versions concernées :

0.5.5
1.6.4
2.2.2
3.0.4

Les versions stables précédentes utilisaient binding.gyp sans lifecycle script explicite.[1]

Les deux prereleases étaient différentes

Les deux versions 0.0.0-* avaient un preinstall malveillant, mais :

"files": ["dist"]

a exclu les fichiers payload des tarballs.[1]

Les 10 publications sont malveillantes, mais leurs chemins d’exécution ne sont pas identiques.

Payload principal : 3FWCvzduYZg.js

Les tarballs stables contenaient un fichier obfusqué :

3FWCvzduYZg.js

de l’ordre de 4,4 à 6,4 Mo.[1]

StepSecurity a montré que 0.5.4 est passé d’environ 41 Ko dans 0.5.3 à plus de 5,6 Mo.[2]

Les variations brutales de taille sont donc un signal utile.

Comportement runtime

Dans des runners isolés, StepSecurity a observé :[2]

Node lance le payload
→ curl télécharge Bun
→ Bun s’exécute dans /tmp/trinnyyyy-*
→ gh auth token
→ Git Credential Manager
→ recherche ssh/scp
→ énumération de processus
→ updater.py temporaire

Des accès à l’API GitHub et au hostname metadata Google Cloud ont aussi été observés.

Quels secrets doivent être considérés exposés ?

Si une version affectée s’est exécutée, tout credential accessible au processus doit être considéré comme potentiellement exposé :

GitHub
npm
SSH
cloud
CI/CD
deployment

Cela ne signifie pas que chaque secret a forcément été exfiltré sur chaque hôte.

Pourquoi une dev dependency peut être critique

« Ce n’est qu’un outil de codegen » n’est pas une défense.

Le malware n’a besoin que de s’exécuter pendant :

npm install
pnpm install
yarn install

Les environnements de développement et CI contiennent souvent les credentials les plus intéressants.

Installer un package est une surface d’exécution

Les package managers prennent en charge :

preinstall
install
postinstall
prepare

et des flows comme node-gyp.

L’installation est donc :

résolution
+
téléchargement
+
exécution potentielle

TeamPCP est-il certainement responsable ?

JFrog, Socket et d’autres chercheurs relient ce code à Mini Shai-Hulud et ses dérivés.[3][4]

Mais l’identité exacte de l’opérateur n’est pas démontrée de façon définitive.

Réutilisation de code, accès résiduel ou copycat restent possibles.[4]

Pourquoi Mini Shai-Hulud revient-il ?

Cette famille d’attaques vise les credentials, CI/CD, GitHub et package registries.[12]

Le modèle récurrent :

compromettre le chemin de release
→ obtenir des droits de publication
→ publier un package crédible
→ s’exécuter chez développeurs/CI
→ voler d’autres credentials

L’incident TanStack de mai était différent

Le 11 mai 2026, le repo Router/Start de TanStack a été compromis.[11]

La chaîne combinait :

  1. pull_request_target,
  2. cache poisoning,
  3. extraction d’un token OIDC de la mémoire du runner.

Résultat :

42 packages
84 versions malveillantes

[11]

Query était aussi sain en mai

TanStack a explicitement déclaré que Query faisait partie des familles non compromises.[11]

Mai :

Router/Start compromis

Août :

générateur tiers pour Query compromis

L’incident de mai a eu de vraies conséquences downstream

OpenAI a confirmé que deux appareils d’employés avaient été affectés par l’incident de mai.[13]

OpenAI a décrit une activité centrée sur les credentials et une exfiltration limitée de matériel credential, tout en indiquant ne pas avoir trouvé de preuve d’accès aux données utilisateurs ni de compromission de systèmes de production ou de propriété intellectuelle.[13]

Août vs mai

Mai

fork PR
→ pull_request_target
→ cache empoisonné
→ release de confiance
→ token OIDC extrait
→ publish

Août

fork PR
→ commentaire public "npm publish"
→ workflow privilégié
→ pnpm install
→ id-token: write
→ Trusted Publishing

[1][2][11]

La voie d’août est plus simple.

Comment vérifier son exposition ?

Cherchez les 10 versions affectées dans :[1]

package-lock.json
pnpm-lock.yaml
yarn.lock
bun.lock
SBOM
logs CI
dependency caches

Ne regardez pas uniquement le package.json actuel.

IOCs principaux

Indicateurs publics :[1][2][5]

3FWCvzduYZg.js
binding.gyp
is_it_this_simple.js
nu.js
/tmp/trinnyyyy-*/bun
/tmp/*/updater.py

Cherchez aussi des téléchargements Bun inattendus, gh auth token, appels Git credential manager et exécution node-gyp anormale.

Remédiation

Si une version affectée s’est exécutée :[1][2]

1. arrêter les builds
2. isoler l’hôte
3. utiliser une machine propre
4. tourner tous les credentials accessibles
5. invalider les sessions
6. examiner les audit logs
7. purger les caches
8. rejeter les artifacts du runner exposé
9. reconstruire proprement

Quelles versions sont propres ?

L’advisory GitHub indique 3.0.2 comme known-good et précise que les versions antérieures au 28 août ne sont pas touchées par cet incident.[1]

StepSecurity cite :

0.5.3
1.6.2
2.2.0
3.0.2

comme prédécesseurs propres.[2]

Le 31 août, npm affiche de nouveau latest = 3.0.2.[6]

Qu’a corrigé le mainteneur ?

Selon l’advisory :[1]

  • suppression du trigger issue_comment,
  • releases sur tag push,
  • révocation du Trusted Publisher npm,
  • rotation des tokens longue durée,
  • retour de latest à 3.0.2,
  • suppression du dist-tag pre,
  • deprecation des 10 versions,
  • demande de suppression à npm.

Snyk classe également cette compromission comme Critical, avec un score CVSS de 9.6, ce qui confirme la gravité de l’exécution de code malveillant à l’installation.[8] Les mesures de hardening ajoutées par TanStack après l’incident de mai sont aussi pertinentes pour les caches, workflows et pipelines de release.[14]

Durcir GitHub Actions

  • Ne jamais exécuter du code de fork dans un job privilégié.
  • Ajouter une vérification d’autorisation sur les commentaires.
  • Limiter id-token: write au vrai job de publication.
  • Séparer build et publish.
  • Utiliser un trusted trigger ou approval.
  • Pinner les Actions tierces à un commit SHA.[9]

Durcir l’installation des dépendances

Contrôles utiles :

  • lockfiles,
  • frozen installs,
  • minimum release age/cooldown,
  • monitoring des nouvelles versions,
  • anomalies de taille,
  • policy sur lifecycle scripts,
  • CI sandboxé,
  • network egress limité,
  • détection de packages malveillants en plus des CVE,
  • SBOM,
  • credentials minimaux.

Trusted Publishing reste utile.[10]

Mais il doit être associé à un Trusted Workflow Design.

Checklist de production

Dependencies

  • Lockfile obligatoire.
  • CI bloque les changements inattendus du lockfile.
  • Release cooldown/minimum age.
  • Pas de nouvelle version directement en production.
  • Monitoring des variations de taille.
  • Inspection des install scripts.
  • binding.gyp inattendu signalé.
  • Détection malware en plus du scan CVE.

GitHub Actions

  • Aucun code de fork dans un contexte privilégié.
  • Authorization gate sur issue_comment.
  • pull_request_target seulement si nécessaire.
  • GITHUB_TOKEN minimal.
  • id-token: write uniquement là où nécessaire.
  • Trusted trigger pour publish.
  • Build séparé du publish.
  • Actions pinnées par SHA.
  • L’automatisation par commentaire a un test négatif pour les utilisateurs non autorisés.
  • Le workflow de release ne checkout jamais le code d’un fork non fiable.

npm

  • Trusted Publisher limité aux workflows nécessaires.
  • Pas de long-lived publish tokens inutiles.
  • Monitoring des publications.
  • Alertes sur releases imprévues.
  • Provenance vérifiée mais jamais considérée comme verdict malware.
  • Runbook de deprecation/revocation.

Runners

  • Runners CI éphémères.
  • Secrets minimaux.
  • Cloud credentials courte durée.
  • SSH keys à scope réduit.
  • Monitoring outbound.
  • Installation sans accès à toute l’infrastructure.
  • EDR/runtime monitoring.
  • Isolation rapide possible.

Incident response

  • Owner défini.
  • Recherche historique des lockfiles possible.
  • Purge des caches CI rapide.
  • Sessions invalidables.
  • Carte des credentials accessibles depuis les runners.
  • Rotation depuis une machine propre.
  • Vérification des publications npm non autorisées.
  • Revue des GitHub audit logs.

Verdict POLPROG

L’incident @7nohe/openapi-react-query-codegen montre très clairement la nouvelle forme des attaques supply-chain.

L’attaquant n’a pas eu besoin de hacker npm, de voler un mot de passe mainteneur, de contourner le 2FA ou de voler un ancien token de publication.

Il a suffi d’exécuter du code non fiable dans un workflow qui possédait déjà une identité de publication légitime.

La frontière de sécurité se déplace donc vers :

CI/CD
workflow triggers
OIDC
release authorization
dependency execution

La deuxième leçon est la provenance.

Elle n’a pas menti : elle a correctement attesté l’origine d’un build malveillant.

La troisième leçon est la précision.

TanStack Query lui-même n’a pas été compromis.

C’est un outil tiers de son écosystème qui l’a été.

Au 31 août, les versions malveillantes sont connues, l’advisory est publié, latest est revenu sur 3.0.2 et le workflow a été modifié.[1][6]

La question pour les équipes JavaScript n’est donc pas seulement :

Utilisions-nous ce package ?

Mais surtout :

Un input non fiable peut-il atteindre chez nous un job disposant de droits de publication ?

Si la réponse n’est pas immédiatement claire, il faut auditer GitHub Actions.

Mini Shai-Hulud npm supply chain TanStack Query openapi-react-query-codegen GitHub Actions Trusted Publishing OIDC npm provenance DevSecOps

Questions fréquentes

TanStack Query a-t-il été hacké ?

Non.

Quel paquet a été compromis ?

@7nohe/openapi-react-query-codegen.

Combien de versions ?

10.

Quand ?

Le 28 août 2026, principalement entre 20:00 et 20:21 UTC.

Version actuelle propre ?

3.0.2.

Un token npm mainteneur a-t-il été volé ?

Il n’était pas nécessaire. L’attaque a abusé de Trusted Publishing/OIDC.

Pourquoi la provenance était-elle valide ?

Parce que le véritable workflow a publié les versions.

La provenance ne sert donc à rien ?

Si. Elle prouve l’origine, pas l’absence de malware.

binding.gyp peut-il exécuter du code à l’installation ?

Oui, et il a été utilisé ici comme chemin caché via node-gyp.

Que faire après installation ?

Isoler, tourner les credentials depuis une machine propre, analyser les logs et reconstruire l’environnement.

TeamPCP est-il certainement l’opérateur ?

Les preuves publiques ne permettent pas de l’affirmer avec certitude pour cette vague.

Trusted Publishing est-il cassé ?

Non au sens simple. Le workflow auquel il faisait confiance était mal conçu.

Sources et notes

  1. GitHub Security Advisory, GHSA-9pvf-vcx3-x239, 28 août 2026, consulté le 31 août 2026.123456789101112131415161718192021222324
  2. StepSecurity, @7nohe/openapi-react-query-codegen Compromised Through an Exposed npm Publishing Workflow, 28 août 2026.123456789101112131415
  3. Socket, OpenAPI React Query Codegen Compromised in Mini Shai-Hulud npm Supply Chain Attack, 28 août 2026.1234
  4. JFrog Security Research, Shai-Hulud Trinitite Hits @7nohe/openapi-react-query-codegen, 30 août 2026.12
  5. OSV, MAL-2026-15494, 28 août 2026.12
  6. npm, @7nohe/openapi-react-query-codegen, état vérifié le 31 août 2026.123456
  7. npm, @tanstack/react-query, état vérifié le 31 août 2026.12
  8. Snyk, Embedded Malicious Code affecting @7nohe/openapi-react-query-codegen, 28 août 2026.
  9. GitHub Docs, Securely using pull_request_target, consulté le 31 août 2026.12
  10. npm Docs, Trusted publishing for npm packages, consulté le 31 août 2026.123
  11. TanStack, Postmortem: TanStack npm supply-chain compromise, 11 mai 2026, mis à jour le 15 mai 2026.12345
  12. Aikido Security, Mini Shai-Hulud Is Back, 12 mai 2026.
  13. OpenAI, Our response to the TanStack npm supply chain attack, 13 mai 2026, mis à jour ensuite.12
  14. TanStack, Hardening TanStack After the npm Compromise, 12 mai 2026, mis à jour le 15 mai 2026.

Cela vous a-t-il été utile ?

Recevez les nouveaux articles par e-mail

Un court e-mail par nouvel article d'apprentissage. Pas de spam, désinscription en un clic.

Nous utilisons uniquement votre e-mail pour envoyer de nouveaux articles. Aucun partage avec des tiers.

Retour à l'apprentissage