Op 28 augustus 2026 werd het npm-pakket @7nohe/openapi-react-query-codegen gecompromitteerd. Het is een codegenerator die TypeScript-clients en TanStack Query-hooks uit OpenAPI-schema's genereert.[1][2][3]
De aanvaller hoefde geen npm-wachtwoord van een maintainer of een langlevend publish-token te stelen.
De aanval liep via de releaseworkflow in GitHub Actions.
Het repository luisterde naar:
issue_comment
en een pull-requestcomment met exact:
npm publish
kon het releasepad activeren zonder betrouwbaar te controleren of de commenter een maintainer, collaborator of externe GitHub-gebruiker was.[1][2]
Daarna:
checkout van PR-code
→ pnpm install
→ id-token: write
→ npm Trusted Publishing
Het resultaat: 10 kwaadaardige versies werden gepubliceerd met geldige npm provenance.[1][3]
De belangrijkste les:
Provenance kan correct bewijzen waar een build vandaan komt, terwijl die build zelf kwaadaardig is.
Een tweede belangrijk punt: @tanstack/react-query zelf werd in dit incident niet gecompromitteerd. Het getroffen pakket is een onafhankelijk hulpmiddel dat code voor TanStack Query genereert.[6][7]
Informatiestatus: 31 augustus 2026.
TL;DR
| Vraag | Geverifieerd antwoord |
|---|---|
| Getroffen pakket | @7nohe/openapi-react-query-codegen |
| Datum | 28 augustus 2026 |
| Kwaadaardige versies | 10 |
| Stabiele kwaadaardige versies | 8 |
| Kwaadaardige prereleases | 2 |
@tanstack/react-query gecompromitteerd? | Nee |
| Hoofdvector | Onveilig geconfigureerde GitHub Actions issue_comment releaseworkflow |
| Maintainer-wachtwoord nodig? | Nee |
| Langlevend npm-token nodig? | Nee |
| Publish-authoriteit | id-token: write + npm Trusted Publishing |
| Geldige provenance? | Ja |
| Provenance = veilige code? | Nee |
| Uitvoeringspaden | binding.gyp en bij sommige versies ook preinstall |
| Hoofdpayload | 3FWCvzduYZg.js |
Huidige latest | 3.0.2 |
| Severity | Critical, CVSS 9.6 |
| CVE | Geen bekende CVE in het advisory op 31 augustus |
| Campagnefamilie | Activiteit gerelateerd aan/afgeleid van Mini Shai-Hulud |
| Operator definitief toegeschreven? | Nee |
| Prioriteit bij incident | Host isoleren en alle bereikbare credentials vanaf een schone machine roteren |
Wat gebeurde er op 28 augustus?
GitHub Security Advisory GHSA-9pvf-vcx3-x239 vermeldt 10 kwaadaardige versies, gepubliceerd tussen ongeveer 20:00 en 20:21 UTC.[1]
Acht stabiele versies:
0.5.4
0.5.5
1.6.3
1.6.4
2.2.1
2.2.2
3.0.3
3.0.4
en twee prereleases:
0.0.0-365d4eb738d3146583431948d3ba6e27a32556be
0.0.0-ec7876d6c917dad516ba69bbfafc948b834bf0ab
De kwaadaardige latest wees vanaf ongeveer 20:19:29 UTC naar 3.0.4 en werd rond 22:51 UTC teruggezet naar de schone 3.0.2.[1]
TanStack Query zelf was niet getroffen
De formulering:
TanStack Query gehackt
is hier onjuist.
@7nohe/openapi-react-query-codegen is een onafhankelijk project dat code genereert voor:
@tanstack/react-query
Dat is een technische relatie, geen eigendomsrelatie.
Het officiële npm-pakket @tanstack/react-query staat apart, en TanStacks officiële postmortem van de aanval in mei noemde Query expliciet als niet getroffen.[7][11]
Wat doet openapi-react-query-codegen?
Het genereert onder andere:
- typed API-clients,
- query keys,
queryOptions,infiniteQueryOptions,useQuery,useMutation,- suspense-helpers,
- prefetch- en SSR-helpers.
Typische flow:
OpenAPI schema
↓
openapi-react-query-codegen
↓
TypeScript client
↓
TanStack Query hooks/options
Het is doorgaans een development dependency.
Juist daar kan install-time malware veel waardevolle toegang hebben.
Hoe populair was het pakket?
Op 31 augustus liet npm ongeveer 155.000 wekelijkse downloads zien.[6]
Dat is een dynamische momentopname.
Belangrijker is dat een codegenerator draait op ontwikkelaarsmachines en CI-runners, vaak in de buurt van GitHub-, SSH-, cloud- en deploymentcredentials.
De aanval begon in GitHub Actions
De workflow luisterde naar:
on:
issue_comment:
types: [created]
issue_comment is op zichzelf geen kwetsbaarheid.
De gevaarlijke combinatie was:
externe comment
+
geen authorisatiecontrole
+
checkout PR-code
+
code-uitvoering
+
id-token: write
+
publish
Eén comment kon het releasepad activeren
De workflow controleerde vooral of de comment bij een pull request hoorde en exact npm publish bevatte.[1][2]
Een stevige check op rollen als:
OWNER
MEMBER
COLLABORATOR
ontbrak.
Een externe gebruiker kon dus een fork-PR openen en het geprivilegieerde pad via een comment bereiken.
Checkout van fork-code maakte input uitvoerbaar
Na checkout van de PR-code draaide de pipeline:
pnpm install
Daarmee werd attacker-controlled content uitgevoerd binnen een releasejob met privileges.
GitHub waarschuwt expliciet voor het uitvoeren van niet-vertrouwde PR-code in geprivilegieerde workflows.[9]
id-token: write gaf toegang tot Trusted Publishing
De job had:
permissions:
id-token: write
Dat is op zichzelf legitiem voor npm Trusted Publishing via OIDC.[10]
Het probleem was dat niet-vertrouwde code kon draaien in precies die job die de geldige OIDC-identiteit mocht verkrijgen.
Geen gestolen maintainercredentials nodig
StepSecurity benadrukt dat de aanvaller geen npm-wachtwoord of langlevend publish-token nodig had.[2]
Klassiek model:
token stelen
→ publiceren
Nieuw model:
trusted workflow beïnvloeden
→ workflow krijgt legitieme identity
→ publiceren
De beveiligingsgrens verschuift daarmee richting CI/CD.
De kwaadaardige releases hadden geldige provenance
Omdat ze via de echte workflow en Trusted Publishing werden gepubliceerd, kregen ze geldige provenance-attestaties.[1][3]
De provenance kon correct zeggen:
dit artifact kwam
uit dit repository
via deze workflow
Maar niet:
de uitgevoerde PR-code was legitiem en veilig
Provenance is geen malwarescanner
Provenance helpt bij het verifiëren van:
- build-origin,
- workflowidentity,
- koppeling aan source,
- chain of custody.
Het garandeert niet automatisch:
- veilige sourcecode,
- geautoriseerde PR,
- veilige workflowlogica,
- afwezigheid van malware.
Daarom:
valid provenance
≠
safe package
npm beschrijft Trusted Publishing als OIDC-gebaseerde publicatie en provenance als oorsprongsbewijs, niet als universele malware-uitspraak.[10]
Eerste uitvoeringspad: binding.gyp
Sommige stabiele kwaadaardige releases hadden geen zichtbare:
"preinstall": "..."
In plaats daarvan voegden ze:
binding.gyp
toe.
De GYP/Python-evaluatie werd misbruikt om uiteindelijk os.system() te bereiken en de JavaScript-payload te starten.[1][5]
Alleen lifecycle scripts scannen is dus onvoldoende.
Tweede uitvoeringspad: preinstall
Latere stabiele releases voegden ook toe:
"preinstall": "node 3FWCvzduYZg.js"
Dat gold voor:
0.5.5
1.6.4
2.2.2
3.0.4
De eerdere stabiele versies:
0.5.4
1.6.3
2.2.1
3.0.3
gebruikten het binding.gyp-pad zonder expliciete lifecycle script.[1]
De twee prereleases waren anders
De twee 0.0.0-* prereleases hadden een kwaadaardige preinstall-referentie, maar door:
"files": ["dist"]
zaten de payloadbestanden niet in de tarball.[1]
Alle 10 publicaties zijn kwaadaardig, maar technisch niet identiek.
Hoofdpayload: 3FWCvzduYZg.js
De stabiele kwaadaardige tarballs bevatten:
3FWCvzduYZg.js
met een grootte van ongeveer 4,4–6,4 MB afhankelijk van de release.[1]
StepSecurity zag dat 0.5.4 groeide van ongeveer 41 KB in 0.5.3 naar meer dan 5,6 MB.[2]
Een plotselinge package-size delta is daarom een nuttig supply-chain signaal.
Wat deed de payload tijdens uitvoering?
StepSecurity draaide getroffen versies in geïsoleerde GitHub-hosted runners.[2]
Waargenomen gedrag omvatte:
Node start payload
→ curl downloadt Bun
→ Bun draait vanuit /tmp/trinnyyyy-*
→ gh auth token wordt aangeroepen
→ Git Credential Manager wordt bevraagd
→ ssh / scp worden gecontroleerd
→ processen worden geïnventariseerd
→ tijdelijke updater.py draait
Er werd ook contact met de GitHub API en probing van de Google Cloud metadata-hostnaam waargenomen.[2]
Welke secrets moeten als potentieel blootgesteld gelden?
De werkelijke exposure hangt af van wat de gebruiker of CI-runner kon bereiken.
Denk aan:
GitHub credentials
npm credentials
SSH keys
cloud credentials
CI/CD secrets
deployment credentials
source repositories
Als de malware draaide, moeten bereikbare credentials als potentieel gecompromitteerd worden behandeld.
Dat betekent niet dat elk secret daadwerkelijk op ieder systeem is geëxfiltreerd.
Waarom een dev dependency zeer gevaarlijk kan zijn
De gedachte:
het is alleen codegen
het gaat niet naar de browser
is niet relevant voor install-time malware.
Het hoeft alleen te draaien tijdens:
npm install
pnpm install
yarn install
Developer- en CI-systemen bevatten vaak juist de meest waardevolle credentials.
Package install is een code-execution surface
Package managers ondersteunen hooks zoals:
preinstall
install
postinstall
prepare
Daarnaast kunnen native-addonflows tools zoals node-gyp starten.
Installatie is dus in werkelijkheid:
dependency resolution
+
download
+
mogelijke code-uitvoering
Was TeamPCP zeker de operator?
JFrog, Socket en andere onderzoekers koppelen de code aan Mini Shai-Hulud en gerelateerde varianten.[3][4]
Maar de exacte operatorattributie is niet definitief bewezen.
Mogelijkheden zijn:
- dezelfde groep,
- resterende toegang,
- hergebruik van publieke malware,
- copycat.
JFrog wijst expliciet op deze onzekerheid.[4]
Waarom blijft Mini Shai-Hulud terugkomen?
De campagnefamilie focust op credential theft, CI/CD, GitHub, package registries en propagatie.[12]
Terugkerend patroon:
releasepad compromitteren
→ publish authority verkrijgen
→ betrouwbaar ogend pakket publiceren
→ uitvoeren op developer/CI-host
→ meer credentials zoeken
De TanStack-aanval in mei was technisch anders
Op 11 mei 2026 was het Router/Start repository getroffen.[11]
De aanval combineerde:
pull_request_target,- GitHub Actions cache poisoning,
- OIDC-tokenextractie uit runner memory.
Resultaat:
42 packages
84 kwaadaardige versies
Dat is een andere root cause dan de aanval van 28 augustus.
Query was ook in mei schoon
TanStacks officiële postmortem verklaarde dat alleen Router/Start was getroffen en noemde Query expliciet als niet getroffen.[11]
Dus:
mei → Router/Start getroffen
augustus → onafhankelijke Query-codegenerator getroffen
Geen van beide betekent dat @tanstack/react-query besmet was.
De aanval in mei had echte downstream-impact
OpenAI bevestigde dat twee apparaten van medewerkers werden geraakt door de TanStack/Mini Shai-Hulud-aanval van mei.[13]
OpenAI meldde credentialgerichte activiteit en beperkte exfiltratie van credentialmateriaal uit een subset van repositories, maar geen bewijs voor toegang tot gebruikersdata of compromittering van productiesystemen of intellectueel eigendom.[13]
Dit laat zien dat zelfs een korte exposurewindow relevant kan zijn.
Augustus versus mei
Mei
fork PR
→ pull_request_target
→ poisoned cache
→ trusted release herstelt cache
→ OIDC token uit geheugen
→ publish
Augustus
fork PR
→ publieke "npm publish"-comment
→ privileged workflow checkt PR uit
→ pnpm install voert attacker-code uit
→ job heeft id-token: write
→ Trusted Publishing
De augustusroute was eenvoudiger.
Hoe controleer je of je project geraakt is?
Zoek alle 10 getroffen versies in lockfiles en historische CI-data.[1]
Controleer:
package-lock.json
pnpm-lock.yaml
yarn.lock
bun.lock
SBOM
CI install logs
dependency caches
Alleen het huidige package.json bekijken is onvoldoende.
Belangrijke IOC's
Publieke indicators zijn onder meer:[1][2][5]
3FWCvzduYZg.js
binding.gyp
is_it_this_simple.js
nu.js
/tmp/trinnyyyy-*/bun
/tmp/*/updater.py
Controleer ook op onverwachte Bun-downloads, gh auth token, Git Credential Manager-calls en node-gyp-uitvoering in een pakket dat geen native code nodig zou moeten hebben.
Wat te doen na een getroffen installatie?
GitHub advisory en StepSecurity adviseren de host als mogelijk gecompromitteerd te behandelen.[1][2]
Minimumrespons:
1. stop builds
2. isoleer host
3. gebruik een aparte schone machine
4. roteer alle bereikbare credentials
5. invalideer actieve sessions
6. controleer GitHub/npm/cloud audit logs
7. verwijder dependency caches
8. verwerp artifacts van de getroffen runner
9. rebuild vanuit schone inputs
Roteer niet alleen het npm-token.
Welke versies zijn schoon?
GitHub advisory noemt 3.0.2 als known-good en stelt dat versies van vóór 28 augustus niet door dit incident getroffen zijn.[1]
StepSecurity noemt als schone voorgangers:
0.5.3
1.6.2
2.2.0
3.0.2
Op 31 augustus toont npm weer:
latest = 3.0.2
Wat veranderde upstream?
Volgens het advisory:[1]
issue_comment-trigger verwijderd,- releases naar tag push verplaatst,
- npm Trusted Publisher revoked,
- long-lived tokens geroteerd,
latestteruggezet naar3.0.2,predist-tag verwijderd,- alle 10 kwaadaardige versies deprecated,
- verwijdering bij npm security aangevraagd.
Snyk classificeert de compromittering eveneens als Critical met CVSS 9.6, wat de ernst van kwaadaardige code-uitvoering tijdens installatie bevestigt.[8] Ook TanStacks aanvullende hardening na het incident in mei is relevante context voor caches, workflows en releasepipelines.[14]
GitHub Actions hardenen
- Voer untrusted PR-code nooit uit in een privileged job.
- Voeg actor authorization toe aan comment-driven workflows.
- Geef
id-token: writealleen aan de echte publishjob. - Scheid build en publish.
- Gebruik trusted triggers of approval.
- Pin third-party Actions op commit SHA.[9]
Dependency installation hardenen
Praktische controls:
- lockfiles,
- frozen installs,
- minimum release age/cooldown,
- monitoring van nieuwe releases,
- package-size anomaly detection,
- lifecycle-script policy,
- sandboxed CI,
- outbound network restrictions,
- malicious-package scanning naast CVE-scanning,
- SBOM,
- minimale credentials op runners.
npm Trusted Publishing blijft nuttig.[10]
Maar:
Trusted Publishing
moet samengaan met:
Trusted Workflow Design
Productiechecklist
Dependencies
- Lockfile is verplicht.
- CI blokkeert onverwachte lockfilewijzigingen.
- Minimum release age/cooldown.
- Nieuwe versies gaan niet direct naar productie.
- Package-size changes worden gemonitord.
- Install scripts worden gecontroleerd.
- Onverwachte
binding.gypwordt gemarkeerd. - Malwarescanning naast CVE-scanning.
GitHub Actions
- Forkcode draait nooit privileged.
-
issue_commentheeft authorization gate. -
pull_request_targetalleen indien echt nodig. -
GITHUB_TOKENleast privilege. -
id-token: writealleen waar nodig. - Publish vereist trusted trigger.
- Build en publish zijn gescheiden.
- Actions zijn op SHA gepind.
- Comment-driven automation heeft een negatieve test voor niet-geautoriseerde gebruikers.
- Releaseworkflows checken nooit code uit een niet-vertrouwde fork uit.
npm
- Trusted Publisher beperkt tot noodzakelijke workflows.
- Geen onnodige long-lived publish tokens.
- Realtime publish monitoring.
- Alerts voor onverwachte releases.
- Provenance wordt geverifieerd maar nooit als malware verdict gebruikt.
- Runbook voor deprecation/revocation.
Runners en endpoints
- CI runners zijn ephemeral.
- Minimale secrets in workspace.
- Cloud credentials zijn short-lived.
- SSH keys minimaal gescoped.
- Outbound traffic wordt gemonitord.
- Dependency install heeft geen brede infra-toegang.
- EDR/runtime monitoring aanwezig.
- Host snel isoleerbaar.
Incident response
- Owner is gedefinieerd.
- Historische lockfile search mogelijk.
- CI caches snel te wissen.
- Sessions snel invalideerbaar.
- Credential exposure van runners is in kaart.
- Rotatie gebeurt vanaf clean machine.
- npm wordt gecontroleerd op ongeautoriseerde publishes.
- GitHub audit logs worden onderzocht.
POLPROG-oordeel
De compromittering van @7nohe/openapi-react-query-codegen is een van de duidelijkste voorbeelden uit 2026 van hoe software supply-chain attacks veranderen.
De aanvaller hoefde niet:
npm te hacken
een maintainer-wachtwoord te stelen
2FA te omzeilen
een klassiek publish-token te stelen
Het volstond om niet-vertrouwde code uit te voeren in een workflow die al een legitieme publish identity had.
De moderne trust boundary verschuift richting:
CI/CD
workflow triggers
OIDC
release authorization
dependency execution
Tweede les: provenance.
Geldige provenance was hier niet fout. Ze bevestigde correct de oorsprong van een kwaadaardige build.
Derde les: precisie.
TanStack Query zelf werd niet gecompromitteerd.
Een onafhankelijk hulpmiddel uit het ecosysteem werd getroffen.
Op 31 augustus zijn de kwaadaardige versies bekend, het advisory is gepubliceerd, latest is terug op 3.0.2 en de releaseworkflow is gewijzigd.[1][6]
De belangrijkste vraag voor JavaScriptteams is daarom niet alleen:
Gebruikten wij dit pakket?
Maar:
Kan in onze eigen releasepipeline niet-vertrouwde input een job met publish authority bereiken?
Als het antwoord niet direct duidelijk is, is een GitHub Actions-audit verstandig.

