Dne 28. srpna 2026 byl kompromitován npm balíček @7nohe/openapi-react-query-codegen, nástroj generující TypeScript klienty a hooky pro TanStack Query z OpenAPI schémat.[1][2][3]
Útočník nepotřeboval npm heslo maintainera ani ukradený dlouhodobý publish token.
Cesta vedla přes release workflow v GitHub Actions.
Repozitář reagoval na:
issue_comment
a komentář v pull requestu s přesným textem:
npm publish
mohl spustit release flow bez dostatečného ověření, zda komentující je maintainer, collaborator nebo úplně externí uživatel GitHubu.[1][2]
Workflow potom:
checkoutoval kód z PR
→ spustil pnpm install
→ měl id-token: write
→ publikoval přes npm Trusted Publishing
Výsledkem bylo 10 škodlivých verzí publikovaných s platnou npm provenance.[1][3]
Hlavní ponaučení:
Provenance může správně potvrdit původ buildu, i když je samotný build škodlivý.
Je nutná i důležitá korekce: @tanstack/react-query samotný nebyl v tomto incidentu kompromitován. Napaden byl nezávislý code generator používaný s TanStack Query.[6][7]
Stav informací: 31. srpna 2026.
TL;DR
| Otázka | Ověřená odpověď |
|---|---|
| Napadený balíček | @7nohe/openapi-react-query-codegen |
| Datum | 28. srpna 2026 |
| Škodlivých verzí | 10 |
| Stabilních škodlivých verzí | 8 |
| Škodlivých prerelease | 2 |
@tanstack/react-query kompromitován? | Ne |
| Hlavní vektor | Chybně navržený GitHub Actions issue_comment release workflow |
| Potřebné heslo maintainera? | Ne |
| Potřebný long-lived npm token? | Ne |
| Publish oprávnění | id-token: write + npm Trusted Publishing |
| Platná provenance? | Ano |
| Provenance = bezpečný kód? | Ne |
| Execution paths | binding.gyp, u části verzí také preinstall |
| Hlavní payload | 3FWCvzduYZg.js |
Aktuální latest | 3.0.2 |
| Severity | Critical, CVSS 9.6 |
| CVE | K 31. srpnu advisory neuvádí známé CVE |
| Rodina | Aktivita spojovaná s Mini Shai-Hulud / jeho deriváty |
| Jistá atribuce operátora? | Ne |
| Prioritní reakce | Izolovat host a z čistého stroje rotovat všechny dostupné credentials |
Co se stalo 28. srpna?
GitHub Security Advisory GHSA-9pvf-vcx3-x239 uvádí 10 škodlivých verzí publikovaných přibližně mezi 20:00 a 20:21 UTC.[1]
Osm stabilních verzí:
0.5.4
0.5.5
1.6.3
1.6.4
2.2.1
2.2.2
3.0.3
3.0.4
a dva prerelease:
0.0.0-365d4eb738d3146583431948d3ba6e27a32556be
0.0.0-ec7876d6c917dad516ba69bbfafc948b834bf0ab
Tag latest ukazoval na škodlivé 3.0.4 zhruba od 20:19:29 UTC do přibližně 22:51 UTC, kdy byl vrácen na čisté 3.0.2.[1]
TanStack Query samotný nebyl napaden
Titulek:
TanStack Query hacked
je nepřesný.
@7nohe/openapi-react-query-codegen je nezávislý projekt, který generuje kód pro:
@tanstack/react-query
Jde o technologické propojení, ne o oficiální TanStack balíček.
Oficiální npm stránka @tanstack/react-query je samostatná a TanStack ve svém květnovém postmortemu rovněž výslovně uvedl Query mezi nepostiženými rodinami.[7][11]
Co openapi-react-query-codegen dělá?
Generuje například:
- typed API clients,
- query keys,
queryOptions,infiniteQueryOptions,useQuery,useMutation,- suspense helpery,
- prefetch a SSR helpery.
Typický tok:
OpenAPI schema
↓
openapi-react-query-codegen
↓
TypeScript client
↓
TanStack Query hooks/options
Jde typicky o dev dependency, což z pohledu install-time malware neznamená nižší riziko.
Jak rozšířený byl balíček?
K 31. srpnu npm ukazoval přibližně 155 tisíc stažení týdně.[6]
Jde o dynamickou metriku.
Podstatnější je, že codegen běží na vývojářských strojích a CI runnerech, často v prostředí s GitHub, SSH, cloud a deployment credentials.
Útok začal v GitHub Actions
Release workflow naslouchal:
on:
issue_comment:
types: [created]
Samotný issue_comment není zranitelnost.
Nebezpečná byla kombinace:
externí komentář
+
žádná autorizace autora
+
checkout PR kódu
+
spuštění kódu
+
id-token: write
+
publish
Jeden komentář mohl otevřít release path
Workflow v zásadě ověřoval, zda komentář patřil k pull requestu a jeho obsah byl přesně npm publish.[1][2]
Chyběl spolehlivý authorization gate pro role jako:
OWNER
MEMBER
COLLABORATOR
Externí účet mohl otevřít fork PR a komentářem dosáhnout na privilegovaný job.
Checkout forku změnil input na code execution
Po checkoutu PR kódu workflow spustil:
pnpm install
Attacker-controlled obsah tak byl vykonán v release jobu s vysokými právy.
GitHub dlouhodobě doporučuje nespouštět nedůvěryhodný PR kód v privilegovaných workflows.[9]
id-token: write umožnil Trusted Publishing
Job měl:
permissions:
id-token: write
To je legitimní permission pro npm Trusted Publishing přes OIDC.[10]
Problém nebyl OIDC samotný.
Problém byl, že útočníkův kód běžel v jobu oprávněném získat důvěryhodnou workload identity.
Nebylo nutné ukrást heslo ani token
StepSecurity zdůrazňuje, že útočník nepotřeboval maintainerovo npm heslo ani dlouhodobý publish token.[2]
Starý threat model:
ukrást token
→ publish
Nový model:
ovlivnit trusted workflow
→ workflow získá platnou identity
→ publish
Bezpečnostní hranice se tak přesouvá z účtu do CI/CD architektury.
Škodlivé release měly platnou provenance
Publikace proběhly přes skutečný workflow a Trusted Publishing, proto měly platné provenance attestations.[1][3]
Provenance správně potvrzovala:
tento artifact pochází
z tohoto repository
přes tento workflow
Neřešila však, zda kód checkoutovaný z PR byl legitimní.
Provenance není malware scanner
Provenance může potvrdit:
- původ buildu,
- identitu workflow,
- vazbu na source,
- chain of custody.
Automaticky nepotvrzuje:
- bezpečný source code,
- autorizovaný PR,
- bezpečnou workflow logiku,
- absenci malware.
Proto:
valid provenance
≠
safe package
npm Trusted Publishing používá OIDC k autentizaci workloadu a provenance k doložení původu, nikoli jako univerzální malware verdict.[10]
První execution path: binding.gyp
Některé stabilní škodlivé verze neměly viditelný:
"preinstall": "..."
Místo toho přidaly:
binding.gyp
GYP/Python evaluace byla zneužita tak, aby nakonec spustila JavaScript payload přes systémový příkaz.[1][5]
Security scanner, který kontroluje jen lifecycle scripts v package.json, by tuto cestu mohl minout.
Druhá cesta: preinstall
Další stabilní release přidaly:
"preinstall": "node 3FWCvzduYZg.js"
Konkrétně:
0.5.5
1.6.4
2.2.2
3.0.4
Předchozí stabilní verze:
0.5.4
1.6.3
2.2.1
3.0.3
používaly binding.gyp bez explicitního lifecycle scriptu.[1]
Dva prerelease byly odlišné
Dva 0.0.0-* prerelease obsahovaly škodlivý preinstall, ale kvůli:
"files": ["dist"]
nebyly odkazované payload files v tarballu.[1]
Všech 10 publikací je klasifikováno jako škodlivých, ale nejde o identické artefakty se stejnou execution path.
Hlavní payload: 3FWCvzduYZg.js
Stabilní škodlivé tarbally obsahovaly:
3FWCvzduYZg.js
o velikosti zhruba 4,4 až 6,4 MB podle verze.[1]
StepSecurity ukázal, že 0.5.4 narostla z přibližně 41 KB u 0.5.3 na více než 5,6 MB.[2]
Náhlá změna velikosti balíčku je užitečný supply-chain anomaly signal.
Co payload dělal za běhu?
StepSecurity detonoval postižené verze v izolovaných GitHub-hosted runnerech.[2]
Pozorované chování zahrnovalo:
Node spustí payload
→ curl stáhne Bun
→ Bun běží z /tmp/trinnyyyy-*
→ volá se gh auth token
→ dotazuje se Git Credential Manager
→ kontroluje ssh / scp
→ enumerují se procesy
→ spouští se dočasný updater.py
Pozorován byl také přístup k GitHub API a probing Google Cloud metadata hostname.[2]
Jde o malware zaměřený na credentials.
Které credentials považovat za ohrožené?
Skutečný rozsah závisí na oprávněních procesu.
Pokud se škodlivá verze spustila, za potenciálně exponované považujte vše, co proces mohl číst:
GitHub
npm
SSH
cloud
CI/CD
deployment
source repositories
Neznamená to, že každý secret byl na každém stroji skutečně exfiltrován.
Proč je dev dependency nebezpečná
Argument:
je to jen codegen
do browser bundle se nedostane
neřeší install-time malware.
Payload stačí spustit během:
npm install
pnpm install
yarn install
Developer a CI prostředí často mají nejcitlivější credentials z celého software lifecycle.
Package install je code-execution surface
Package managers podporují hooks:
preinstall
install
postinstall
prepare
a native addon flows mohou spustit node-gyp.
Instalace tedy znamená:
dependency resolution
+
download
+
potenciální code execution
Je jisté, že šlo o TeamPCP?
JFrog, Socket a další výzkumníci spojují payload s Mini Shai-Hulud a příbuznými variantami.[3][4]
Přesná atribuce operátora však není veřejně definitivně doložena.
Možné je:
- pokračování stejného aktéra,
- zbytkový přístup,
- reuse známého malware,
- copycat.
JFrog tuto nejistotu výslovně zmiňuje.[4]
Proč se Mini Shai-Hulud vrací?
Tato rodina kampaní cílí na credential theft, CI/CD, GitHub, package registries a propagaci.[12]
Opakující se model:
proniknout do release cesty
→ získat publish authority
→ vydat důvěryhodně vypadající package
→ spustit se na developer/CI hostu
→ hledat další credentials
Květnový útok na TanStack byl technicky jiný
Dne 11. května 2026 byl zasažen repository Router/Start.[11]
Útok kombinoval:
pull_request_target,- GitHub Actions cache poisoning,
- extrakci OIDC tokenu z paměti runneru.
Výsledek:
42 packages
84 škodlivých verzí
To není stejný root cause jako 28. srpna.
Query byl čistý i v květnu
TanStack ve svém oficiálním postmortemu uvedl, že napaden byl pouze Router/Start a Query patřil mezi nepostižené rodiny.[11]
Proto:
květen → Router/Start
srpen → nezávislý codegen pro Query
Ani jeden případ neznamená kompromitaci @tanstack/react-query.
Květnový incident měl skutečný downstream dopad
OpenAI potvrdilo, že dvě zařízení zaměstnanců byla květnovým TanStack/Mini Shai-Hulud útokem zasažena.[13]
OpenAI popsalo credential-focused aktivitu a omezenou exfiltraci credential materiálu z části repozitářů, ale nenašlo důkazy o přístupu k user data ani kompromitaci produkčních systémů nebo IP.[13]
Krátké exposure window tedy nemusí znamenat malý dopad.
Srpen vs květen
Květen
fork PR
→ pull_request_target
→ poisoned cache
→ trusted release obnoví cache
→ OIDC token z paměti
→ publish
Srpen
fork PR
→ veřejný komentář "npm publish"
→ privileged workflow checkoutuje PR
→ pnpm install spustí attacker code
→ job už má id-token: write
→ Trusted Publishing
Srpnová cesta byla jednodušší.
Jak zjistit, zda projekt byl zasažen?
Prohledejte všechny lockfiles, SBOM a historické CI záznamy pro všech 10 verzí.[1]
Kontrolujte:
package-lock.json
pnpm-lock.yaml
yarn.lock
bun.lock
SBOM
CI install logs
dependency caches
Aktuální package.json nestačí.
Důležité IOC
Veřejně známé indikátory:[1][2][5]
3FWCvzduYZg.js
binding.gyp
is_it_this_simple.js
nu.js
/tmp/trinnyyyy-*/bun
/tmp/*/updater.py
Hledejte také neočekávané stahování Bun, gh auth token, Git Credential Manager calls a nečekaný node-gyp v balíčku, který nepotřebuje native code.
Co dělat po zasažené instalaci?
GitHub advisory a StepSecurity doporučují považovat host za potenciálně kompromitovaný.[1][2]
Minimální reakce:
1. zastavit buildy
2. izolovat host
3. použít oddělený čistý stroj
4. rotovat všechny dostupné credentials
5. invalidovat sessions
6. prověřit GitHub/npm/cloud audit logs
7. odstranit dependency caches
8. zahodit artifacts ze zasaženého runneru
9. rebuildovat z čistých vstupů
Nestačí rotovat pouze npm token.
Které verze jsou bezpečné?
GitHub advisory označuje 3.0.2 jako known-good a uvádí, že verze publikované před 28. srpnem nejsou tímto incidentem zasažené.[1]
StepSecurity uvádí čisté předchůdce:
0.5.3
1.6.2
2.2.0
3.0.2
Dne 31. srpna npm znovu ukazuje:
latest = 3.0.2
Co upstream opravil?
Podle advisory:[1]
- odstranil
issue_commenttrigger, - release přesunul na tag push,
- revoked npm Trusted Publisher,
- rotoval long-lived tokeny,
- vrátil
latestna3.0.2, - odstranil
predist-tag, - deprecated všech 10 škodlivých verzí,
- požádal npm o odstranění.
Snyk rovněž klasifikuje kompromitaci jako Critical s CVSS 9.6, což potvrzuje závažnost spuštění škodlivého kódu při instalaci.[8] Relevantní jsou také další hardening kroky, které TanStack po květnovém incidentu zavedl pro cache, workflows a release pipeline.[14]
Jak hardenovat GitHub Actions
- Nikdy nespouštět untrusted PR code v privileged job.
- U comment-driven workflows ověřovat authorization aktéra.
id-token: writedát pouze skutečnému publish jobu.- Oddělit build od publish.
- Používat trusted trigger nebo approval.
- Third-party Actions pinovat na commit SHA.[9]
Jak hardenovat instalaci dependencies
Praktické kontroly:
- lockfiles,
- frozen installs,
- minimum release age/cooldown,
- monitoring nových publishů,
- package-size anomaly detection,
- lifecycle-script policy,
- sandboxované CI,
- omezení outbound network,
- malicious-package scanning vedle CVE,
- SBOM,
- minimální credentials na runnerech.
npm Trusted Publishing zůstává užitečné.[10]
Ale:
Trusted Publishing
musí být spojeno s:
Trusted Workflow Design
Produkční checklist
Dependencies
- Lockfile je povinný.
- CI blokuje neočekávané změny lockfile.
- Minimum release age/cooldown.
- Nová verze nejde okamžitě do produkce.
- Sledujeme package-size změny.
- Kontrolujeme install scripts.
- Neočekávané
binding.gypvyvolá alert. - Malware scanning doplňuje CVE scanning.
GitHub Actions
- Fork code nikdy neběží privileged.
-
issue_commentmá authorization gate. -
pull_request_targetpouze když je nutný. -
GITHUB_TOKENmá least privilege. -
id-token: writejen kde je potřeba. - Publish vyžaduje trusted trigger.
- Build a publish jsou oddělené.
- Actions jsou pinované na SHA.
- Comment-driven automatizace má negativní test pro neautorizovaného uživatele.
- Release workflow nikdy necheckoutuje kód z nedůvěryhodného forku.
npm
- Trusted Publisher je omezen na nezbytné workflows.
- Nemáme zbytečné long-lived publish tokeny.
- Publish monitorujeme realtime.
- Neplánovaný release vyvolá alert.
- Provenance ověřujeme, ale nepovažujeme za malware verdict.
- Máme runbook pro deprecation/revocation.
Runnery a endpointy
- CI runner je ephemeral.
- Workspace obsahuje minimum secretů.
- Cloud credentials jsou short-lived.
- SSH keys mají minimální scope.
- Outbound traffic je monitorován.
- Dependency install nemá široký přístup do infrastruktury.
- Endpointy mají EDR/runtime monitoring.
- Host lze rychle izolovat.
Incident response
- Owner dependency incidentu je určen.
- Umíme historicky hledat v lockfiles.
- Umíme rychle vyčistit CI caches.
- Umíme invalidovat sessions.
- Máme mapu credentials dostupných runneru.
- Rotace probíhá z clean machine.
- Kontrolujeme neautorizované npm publishes.
- Vyhodnocujeme GitHub audit logs.
Verdikt POLPROG
Kompromitace @7nohe/openapi-react-query-codegen je velmi dobrým příkladem toho, jak se v roce 2026 mění software supply-chain attacks.
Útočník nemusel:
hacknout npm
ukrást maintainerovo heslo
obejít 2FA
ukrást klasický publish token
Stačilo dostat untrusted code do workflow, který už měl legitimní publish identity.
Bezpečnostní hranice se tak posouvá k:
CI/CD
workflow triggers
OIDC
release authorization
dependency execution
Druhé ponaučení je provenance.
Platná provenance zde nezklamala. Správně potvrdila původ škodlivého buildu.
Třetí ponaučení je přesnost.
TanStack Query samotný kompromitován nebyl.
Napaden byl nezávislý nástroj jeho ekosystému.
K 31. srpnu jsou škodlivé verze známé, advisory zveřejněné, latest vrácené na 3.0.2 a release workflow upravený.[1][6]
Klíčová otázka pro JavaScript tým tedy není jen:
Používali jsme tento balíček?
Ale:
Může se v našem vlastním release pipeline dostat nedůvěryhodný input do jobu s publish authority?
Pokud odpověď není okamžitě jasná, je čas auditovat GitHub Actions.

