Mini Shai-Hulud атакує openapi-react-query-codegen: 10 шкідливих версій, npm provenance і чому сам TanStack Query не був скомпрометований Skip to content

Mini Shai-Hulud атакує openapi-react-query-codegen: 10 шкідливих версій, npm provenance і чому сам TanStack Query не був скомпрометований

Перевірений аналіз атаки 28 серпня 2026 року на @7nohe/openapi-react-query-codegen: 10 шкідливих версій, GitHub Actions issue_comment, npm Trusted Publishing, валідна provenance, binding.gyp, IOC, remediation та відмінність від TanStack Query.

Опубліковано Автор Час читання 17 хв читання

Перевірений аналіз атаки 28 серпня 2026 року на @7nohe/openapi-react-query-codegen: 10 шкідливих версій, GitHub Actions issue_comment, npm Trusted Publishing, валідна provenance, binding.gyp, IOC, remediation та відмінність від TanStack Query.

На цій сторінці
  1. 1TL;DR
  2. 2Що сталося 28 серпня?
  3. 3TanStack Query сам не був атакований
  4. 4Що робить openapi-react-query-codegen?
  5. 5Наскільки популярним був пакет?
  6. 6Атака почалася в GitHub Actions
  7. 7Один коментар міг відкрити release path
  8. 8Checkout fork-коду перетворив input на code execution
  9. 9id-token: write дозволив Trusted Publishing
  10. 10Не потрібно було красти пароль чи token
  11. 11Шкідливі release мали валідну provenance
  12. 12Provenance не є malware scanner
  13. 13Перший execution path: binding.gyp
  14. 14Другий execution path: preinstall
  15. 15Два prerelease були іншими
  16. 16Основний payload: 3FWCvzduYZg.js
  17. 17Що робив payload у runtime?
  18. 18Які credentials вважати потенційно скомпрометованими?
  19. 19Чому dev dependency може бути критичною
  20. 20Package install є code-execution surface
  21. 21Чи точно це TeamPCP?
  22. 22Чому Mini Shai-Hulud знову з’являється?
  23. 23Травнева атака на TanStack була технічно іншою
  24. 24Query був чистим і в травні
  25. 25Травневий інцидент мав реальний downstream impact
  26. 26Серпень vs травень
  27. 27Як перевірити, чи проєкт був уражений?
  28. 28Важливі IOC
  29. 29Що робити після ураженої інсталяції?
  30. 30Які версії безпечні?
  31. 31Що виправив upstream?
  32. 32Як harden GitHub Actions
  33. 33Як harden dependency installation
  34. 34Production checklist
  35. 35Висновок POLPROG

28 серпня 2026 року було скомпрометовано npm-пакет @7nohe/openapi-react-query-codegen, інструмент, що генерує TypeScript-клієнти та hook-и для TanStack Query зі схем OpenAPI.[1][2][3]

Атакувальнику не знадобилися ні npm-пароль maintainer-а, ні викрадений довгоживучий publish token.

Шлях атаки проходив через release workflow у GitHub Actions.

Репозиторій реагував на:

issue_comment

і коментар у pull request з точним текстом:

npm publish

міг запустити release path без належної перевірки, чи автор коментаря є maintainer, collaborator або повністю зовнішнім користувачем GitHub.[1][2]

Після цього workflow:

checkout-ив код із PR
→ запускав pnpm install
→ мав id-token: write
→ публікував через npm Trusted Publishing

[1][2]

Результат: 10 шкідливих версій було опубліковано з валідною npm provenance.[1][3]

Головний урок:

Provenance може коректно підтверджувати походження build-а, навіть якщо сам build є шкідливим.

Також потрібне важливе уточнення: @tanstack/react-query у цьому інциденті не був скомпрометований. Постраждав незалежний code generator, що використовується з TanStack Query.[6][7]

Стан інформації: 31 серпня 2026 року.

TL;DR

ПитанняПеревірена відповідь
Скомпрометований пакет@7nohe/openapi-react-query-codegen
Дата28 серпня 2026
Шкідливих версій10
Стабільних шкідливих версій8
Шкідливих prerelease2
@tanstack/react-query скомпрометований?Ні
Основний векторНебезпечно спроєктований GitHub Actions issue_comment release workflow
Потрібен пароль maintainer-а?Ні
Потрібен long-lived npm token?Ні
Publish authorityid-token: write + npm Trusted Publishing
Валідна provenance?Так
Provenance = безпечний код?Ні
Execution pathsbinding.gyp, а в частині версій також preinstall
Основний payload3FWCvzduYZg.js
Поточний latest3.0.2
SeverityCritical, CVSS 9.6
CVEСтаном на 31 серпня advisory не вказує відомого CVE
РодинаАктивність, пов’язана з Mini Shai-Hulud / похідними варіантами
Точна атрибуція оператора?Ні
Пріоритетна реакціяІзолювати host і з чистої машини ротувати всі доступні credentials

Що сталося 28 серпня?

GitHub Security Advisory GHSA-9pvf-vcx3-x239 перелічує 10 шкідливих версій, опублікованих приблизно між 20:00 і 20:21 UTC.[1]

Вісім стабільних версій:

0.5.4
0.5.5
1.6.3
1.6.4
2.2.1
2.2.2
3.0.3
3.0.4

і два prerelease:

0.0.0-365d4eb738d3146583431948d3ba6e27a32556be
0.0.0-ec7876d6c917dad516ba69bbfafc948b834bf0ab

[1][2]

Tag latest вказував на шкідливу 3.0.4 приблизно з 20:19:29 UTC до близько 22:51 UTC, коли його повернули на чисту 3.0.2.[1]

TanStack Query сам не був атакований

Формулювання:

TanStack Query hacked

є неточним.

@7nohe/openapi-react-query-codegen — незалежний проєкт, який генерує код для:

@tanstack/react-query

[6]

Це технологічний зв’язок, а не офіційний TanStack package.

Офіційна npm-сторінка @tanstack/react-query є окремою, а TanStack у травневому postmortem також прямо вказав Query серед незачеплених сімейств.[7][11]

Що робить openapi-react-query-codegen?

Він генерує, зокрема:

  • typed API clients,
  • query keys,
  • queryOptions,
  • infiniteQueryOptions,
  • useQuery,
  • useMutation,
  • suspense helpers,
  • prefetch та SSR helpers.

[6]

Типовий потік:

OpenAPI schema
      ↓
openapi-react-query-codegen
      ↓
TypeScript client
      ↓
TanStack Query hooks/options

Зазвичай це dev dependency, але для install-time malware це не означає менший ризик.

Наскільки популярним був пакет?

Станом на 31 серпня npm показував приблизно 155 тисяч завантажень на тиждень.[6]

Це динамічна метрика.

Важливіше те, де запускається codegen: на машинах розробників та CI runners, часто поруч із GitHub, SSH, cloud та deployment credentials.

Атака почалася в GitHub Actions

Release workflow слухав:

on:
  issue_comment:
    types: [created]

[1]

Сам issue_comment не є вразливістю.

Небезпечною була комбінація:

зовнішній коментар
+
відсутність authorization автора
+
checkout PR-коду
+
виконання коду
+
id-token: write
+
publish

Один коментар міг відкрити release path

Workflow фактично перевіряв, чи коментар належить pull request і має точний текст npm publish.[1][2]

Надійної перевірки на ролі:

OWNER
MEMBER
COLLABORATOR

не було.

Зовнішній GitHub account міг відкрити fork PR і коментарем дістатися до привілейованого job.

Checkout fork-коду перетворив input на code execution

Після checkout PR-коду workflow запускав:

pnpm install

[2]

Так attacker-controlled content виконувався всередині release job з високими привілеями.

GitHub давно рекомендує не запускати недовірений PR-код у привілейованих workflows.[9]

id-token: write дозволив Trusted Publishing

Job мав:

permissions:
  id-token: write

[1][2]

Це нормальна permission для npm Trusted Publishing через OIDC.[10]

Проблемою був не сам OIDC.

Проблемою було те, що код атакувальника запускався в job, який мав право отримати trusted workload identity.

Не потрібно було красти пароль чи token

StepSecurity підкреслює, що нападнику не був потрібен ні npm-пароль maintainer-а, ні довгоживучий publish token.[2]

Старий threat model:

вкрасти token
→ publish

Новий:

вплинути на trusted workflow
→ workflow отримує валідну identity
→ publish

Безпекова межа переміщується від account security до CI/CD architecture.

Шкідливі release мали валідну provenance

Публікації пройшли через справжній workflow і Trusted Publishing, тому отримали валідні provenance attestations.[1][3]

Provenance коректно підтверджувала:

цей artifact походить
з цього repository
через цей workflow

Але не визначала, чи PR-код був авторизований та безпечний.

Provenance не є malware scanner

Provenance може підтвердити:

  • походження build,
  • identity workflow,
  • зв’язок із source,
  • chain of custody.

Вона не гарантує автоматично:

  • безпечний source code,
  • авторизований PR,
  • безпечну workflow logic,
  • відсутність malware.

Тому:

valid provenance
≠
safe package

npm Trusted Publishing використовує OIDC для аутентифікації workload, а provenance для підтвердження походження, не як універсальний malware verdict.[10]

Перший execution path: binding.gyp

Деякі стабільні шкідливі версії не мали очевидного:

"preinstall": "..."

[1]

Натомість вони додавали:

binding.gyp

GYP/Python evaluation була використана так, щоб зрештою виконати JavaScript payload системною командою.[1][5]

Scanner, який перевіряє лише lifecycle scripts у package.json, може таку схему пропустити.

Другий execution path: preinstall

Наступні стабільні версії додали:

"preinstall": "node 3FWCvzduYZg.js"

[1][2]

Це:

0.5.5
1.6.4
2.2.2
3.0.4

Попередні стабільні:

0.5.4
1.6.3
2.2.1
3.0.3

використовували binding.gyp без явного lifecycle script.[1]

Два prerelease були іншими

Два 0.0.0-* prerelease містили шкідливий preinstall, але через:

"files": ["dist"]

payload files не потрапили до tarball.[1]

Усі 10 публікацій класифіковані як шкідливі, але технічно це не ідентичні artifacts з однаковою execution path.

Основний payload: 3FWCvzduYZg.js

Стабільні шкідливі tarballs містили:

3FWCvzduYZg.js

розміром приблизно 4,4–6,4 MB залежно від версії.[1]

StepSecurity показав, що 0.5.4 зросла з приблизно 41 KB у 0.5.3 до понад 5,6 MB.[2]

Різкий package-size delta є корисним supply-chain anomaly signal.

Що робив payload у runtime?

StepSecurity запускав уражені версії в ізольованих GitHub-hosted runners.[2]

Спостерігалася така активність:

Node запускає payload
→ curl завантажує Bun
→ Bun працює з /tmp/trinnyyyy-*
→ викликається gh auth token
→ опитується Git Credential Manager
→ перевіряються ssh / scp
→ перелічуються процеси
→ запускається тимчасовий updater.py

Також фіксували доступ до GitHub API та probing Google Cloud metadata hostname.[2]

Це malware, орієнтований на credentials.

Які credentials вважати потенційно скомпрометованими?

Реальний обсяг залежить від привілеїв процесу.

Якщо шкідлива версія виконалася, потенційно exposed є все, до чого мав доступ процес:

GitHub
npm
SSH
cloud
CI/CD
deployment
source repositories

Це не означає, що кожен secret був фактично викрадений на кожному host.

Чому dev dependency може бути критичною

Аргумент:

це лише codegen
в browser bundle не потрапляє

не враховує install-time malware.

Payload достатньо запуститися під час:

npm install
pnpm install
yarn install

Developer та CI environments часто містять найцінніші credentials у всьому software lifecycle.

Package install є code-execution surface

Package managers підтримують:

preinstall
install
postinstall
prepare

а native-addon flows можуть запускати node-gyp.

Тому installation фактично означає:

dependency resolution
+
download
+
potential code execution

Чи точно це TeamPCP?

JFrog, Socket та інші дослідники пов’язують payload із Mini Shai-Hulud та спорідненими варіантами.[3][4]

Але точна атрибуція operator не доведена публічно остаточно.

Можливі:

  • той самий actor,
  • залишковий доступ,
  • reuse malware,
  • copycat.

JFrog прямо відзначає цю невизначеність.[4]

Чому Mini Shai-Hulud знову з’являється?

Ця campaign family орієнтована на credential theft, CI/CD, GitHub, package registries та propagation.[12]

Повторюваний pattern:

увійти через release path
→ отримати publish authority
→ випустити trusted-looking package
→ виконатися на developer/CI host
→ шукати нові credentials

Травнева атака на TanStack була технічно іншою

11 травня 2026 року постраждав repository Router/Start.[11]

Атака поєднувала:

  1. pull_request_target,
  2. GitHub Actions cache poisoning,
  3. витяг OIDC token з пам’яті runner.

Результат:

42 packages
84 шкідливі версії

[11]

Це інший root cause, ніж 28 серпня.

Query був чистим і в травні

TanStack у своєму official postmortem зазначив, що постраждав лише Router/Start, а Query був серед unaffected families.[11]

Отже:

травень → Router/Start
серпень → незалежний codegen для Query

Жоден випадок не означає компрометацію @tanstack/react-query.

Травневий інцидент мав реальний downstream impact

OpenAI підтвердила, що два пристрої співробітників були зачеплені травневою атакою TanStack/Mini Shai-Hulud.[13]

OpenAI описала credential-focused activity та обмежену exfiltration credential material з частини source repositories, але не знайшла доказів доступу до user data чи компрометації production systems або IP.[13]

Коротке exposure window не гарантує малого впливу.

Серпень vs травень

Травень

fork PR
→ pull_request_target
→ poisoned cache
→ trusted release відновлює cache
→ OIDC token із memory
→ publish

[11]

Серпень

fork PR
→ публічний коментар "npm publish"
→ privileged workflow checkout-ить PR
→ pnpm install запускає attacker code
→ job уже має id-token: write
→ Trusted Publishing

[1][2]

Серпневий шлях був простішим.

Як перевірити, чи проєкт був уражений?

Перевірте всі lockfiles, SBOM та історичні CI records на наявність усіх 10 версій.[1]

Зокрема:

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

Поточний package.json недостатній.

Важливі IOC

Публічні indicators:[1][2][5]

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

Також шукайте несподівані Bun downloads, gh auth token, Git Credential Manager calls та node-gyp execution у пакеті, якому native code не потрібен.

Що робити після ураженої інсталяції?

GitHub advisory та StepSecurity рекомендують вважати host потенційно compromised.[1][2]

Мінімальна response:

1. зупинити build
2. ізолювати host
3. використати окрему clean machine
4. ротувати всі доступні credentials
5. invalidate sessions
6. перевірити GitHub/npm/cloud audit logs
7. видалити dependency caches
8. відкинути artifacts з ураженого runner
9. rebuild із чистих inputs

Недостатньо ротувати лише npm token.

Які версії безпечні?

GitHub advisory вказує 3.0.2 як known-good і зазначає, що версії, опубліковані до 28 серпня, цим інцидентом не зачеплені.[1]

StepSecurity вказує чистих попередників:

0.5.3
1.6.2
2.2.0
3.0.2

[2]

31 серпня npm знову показує:

latest = 3.0.2

[6]

Що виправив upstream?

За advisory:[1]

  • видалив issue_comment trigger,
  • переніс release на tag push,
  • revoked npm Trusted Publisher,
  • ротував long-lived tokens,
  • повернув latest на 3.0.2,
  • прибрав pre dist-tag,
  • deprecated усі 10 шкідливих версій,
  • запросив видалення в npm.

Snyk також класифікує компрометацію як Critical із CVSS 9.6, що підтверджує серйозність виконання шкідливого коду під час installation.[8] Важливим контекстом є й додатковий hardening cache, workflows та release pipeline, який TanStack запровадив після травневого інциденту.[14]

Як harden GitHub Actions

  • Ніколи не запускати untrusted PR code у privileged job.
  • Для comment-driven workflows перевіряти authorization actor-а.
  • id-token: write давати лише справжньому publish job.
  • Розділяти build і publish.
  • Використовувати trusted trigger або approval.
  • Third-party Actions pin-ити на commit SHA.[9]

Як harden dependency installation

Практичні controls:

  • lockfiles,
  • frozen installs,
  • minimum release age/cooldown,
  • monitoring нових publish,
  • package-size anomaly detection,
  • lifecycle-script policy,
  • sandboxed CI,
  • outbound network restrictions,
  • malicious-package scanning поряд із CVE,
  • SBOM,
  • мінімальні credentials на runners.

npm Trusted Publishing залишається корисним.[10]

Але:

Trusted Publishing

має поєднуватися з:

Trusted Workflow Design

Production checklist

Dependencies

  • Lockfile обов’язковий.
  • CI блокує несподівані зміни lockfile.
  • Minimum release age/cooldown.
  • Нова версія не потрапляє одразу в production.
  • Моніторимо package-size changes.
  • Перевіряємо install scripts.
  • Несподіваний binding.gyp викликає alert.
  • Malware scanning доповнює CVE scanning.

GitHub Actions

  • Fork code ніколи не виконується privileged.
  • issue_comment має authorization gate.
  • pull_request_target лише коли справді потрібно.
  • GITHUB_TOKEN має least privilege.
  • id-token: write лише там, де необхідно.
  • Publish потребує trusted trigger.
  • Build і publish розділені.
  • Actions pinned to SHA.
  • Comment-driven automation має негативний test для неавторизованого користувача.
  • Release workflow ніколи не checkout-ить код із недовіреного fork.

npm

  • Trusted Publisher обмежений необхідними workflows.
  • Немає зайвих long-lived publish tokens.
  • Publish моніториться realtime.
  • Незапланований release викликає alert.
  • Provenance перевіряється, але не вважається malware verdict.
  • Є runbook для deprecation/revocation.

Runners та endpoints

  • CI runner ephemeral.
  • Мінімум secrets у workspace.
  • Cloud credentials short-lived.
  • SSH keys мають мінімальний scope.
  • Outbound traffic моніториться.
  • Dependency install не має широкого доступу до infrastructure.
  • Endpoint-и мають EDR/runtime monitoring.
  • Host можна швидко ізолювати.

Incident response

  • Owner dependency incident визначений.
  • Можливий історичний search у lockfiles.
  • CI caches можна швидко очистити.
  • Sessions можна invalidувати.
  • Є карта credentials, доступних runner.
  • Rotation виконується з clean machine.
  • Перевіряються unauthorized npm publishes.
  • Аналізуються GitHub audit logs.

Висновок POLPROG

Компрометація @7nohe/openapi-react-query-codegen є дуже показовим прикладом того, як у 2026 році змінюються software supply-chain attacks.

Атакувальнику не потрібно було:

зламувати npm
красти пароль maintainer-а
обходити 2FA
красти класичний publish token

Достатньо було домогтися виконання untrusted code у workflow, який уже мав легітимну publish identity.

Безпекова межа зміщується до:

CI/CD
workflow triggers
OIDC
release authorization
dependency execution

Другий урок — provenance.

Валідна provenance тут не «помилилася». Вона правильно підтвердила походження шкідливого build-а.

Третій урок — точність.

TanStack Query сам не був скомпрометований.

Постраждав незалежний інструмент його екосистеми.

Станом на 31 серпня шкідливі версії відомі, advisory опублікований, latest повернуто на 3.0.2, а release workflow змінено.[1][6]

Ключове питання для JavaScript-команди не лише:

Чи використовували ми цей package?

А:

Чи може в нашому release pipeline недовірений input потрапити до job із publish authority?

Якщо відповідь не очевидна одразу, варто провести аудит GitHub Actions.

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

Часті запитання

TanStack Query був зламаний?

Ні.

Що було скомпрометовано?

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

Скільки шкідливих версій?

10.

Коли?

28 серпня 2026 року, основна хвиля приблизно між 20:00 і 20:21 UTC.

Яка поточна чиста версія?

3.0.2.

Чи був украдений npm token maintainer-а?

Він не був потрібен. Атака зловжила Trusted Publishing/OIDC.

Чому provenance була валідна?

Тому що публікував справжній trusted workflow.

Provenance тоді не має сенсу?

Має. Вона підтверджує походження, а не відсутність malware.

Чи може binding.gyp виконати код під час npm install?

Так. У цьому інциденті зловживали execution path через node-gyp.

Що робити після інсталяції ураженої версії?

Ізолювати host, з clean machine ротувати credentials, перевірити logs і перевстановити середовище з чистих inputs.

TeamPCP точно є оператором?

Публічних доказів недостатньо для абсолютної атрибуції цієї конкретної хвилі.

Trusted Publishing зламаний?

Не в такому простому сенсі. Головною проблемою був небезпечний workflow design.

Джерела та примітки

  1. GitHub Security Advisory, GHSA-9pvf-vcx3-x239, 28 серпня 2026, доступ 31 серпня 2026.123456789101112131415161718192021222324
  2. StepSecurity, @7nohe/openapi-react-query-codegen Compromised Through an Exposed npm Publishing Workflow, 28 серпня 2026.12345678910111213141516
  3. Socket, OpenAPI React Query Codegen Compromised in Mini Shai-Hulud npm Supply Chain Attack, 28 серпня 2026.1234
  4. JFrog Security Research, Shai-Hulud Trinitite Hits @7nohe/openapi-react-query-codegen, 30 серпня 2026.12
  5. OSV, MAL-2026-15494, 28 серпня 2026.12
  6. npm, @7nohe/openapi-react-query-codegen, стан перевірено 31 серпня 2026.123456
  7. npm, @tanstack/react-query, стан перевірено 31 серпня 2026.12
  8. Snyk, Embedded Malicious Code affecting @7nohe/openapi-react-query-codegen, 28 серпня 2026.
  9. GitHub Docs, Securely using pull_request_target, доступ 31 серпня 2026.12
  10. npm Docs, Trusted publishing for npm packages, доступ 31 серпня 2026.123
  11. TanStack, Postmortem: TanStack npm supply-chain compromise, 11 травня 2026, оновлено 15 травня 2026.12345
  12. Aikido Security, Mini Shai-Hulud Is Back, 12 травня 2026.
  13. OpenAI, Our response to the TanStack npm supply chain attack, 13 травня 2026, пізніше оновлено.12
  14. TanStack, Hardening TanStack After the npm Compromise, 12 травня 2026, оновлено 15 травня 2026.

Чи було це корисно?

Отримуйте нові статті електронною поштою

Один короткий лист на кожну нову статтю Навчання. Без спаму, відписка в один клік.

Ми використовуємо вашу пошту лише для надсилання нових статей. Без передачі третім сторонам.

Назад до Навчання

Усі статті

Показати все