`@7nohe/openapi-react-query-codegen` compromised - "Trinitite" (Mini Shai-Hulud continuation) worm published 10 poisoned versions via a fork PR + `issue_comment` trigger without an author-association gate
On 2026-08-28 an attacker published 10 malicious versions of @7nohe/openapi-react-query-codegen (~150K npm weekly downloads) in a ~20-minute window. Root cause: an issue_comment-triggered GitHub Actions release workflow without an author-association gate - any GitHub user could open a fork PR, comment npm publish, and the pipeline checked out the fork, ran pnpm install (executing the attacker's preinstall hook) with id-token: write and minted an npm OIDC trusted-publishing token to ship the poisoned versions. Payload is a "Trinitite: Sponsored by Preview 2 Effects" credential-stealer worm continuing the Mini Shai-Hulud / TeamPCP lineage.
- Threat actor
- TeamPCP (attributed) - "Trinitite" campaign
- Detected by
- Aikido Security · SafeDep · GitHub Advisory Database
- Also known as
- Trinitite · Trinitite: Sponsored by Preview 2 Effects · Mini Shai-Hulud (openapi-react-query-codegen wave) · openapi-react-query-codegen 2026-08-28 compromise
- Ecosystems
- npm
- Packages tracked
- 1
What happened
On 2026-08-28 an attacker published 10 malicious versions of the popular npm package @7nohe/openapi-react-query-codegen (a TanStack Query codegen against OpenAPI schemas, ~150K npm weekly downloads) within a ~20-minute window. The payload is a self-propagating credential-stealing worm calling itself Trinitite: Sponsored by Preview 2 Effects - a direct continuation of the TeamPCP / Mini Shai-Hulud lineage tracked in Shai-Hulud (2025-09), Mini Shai-Hulud Wave 2 (2026-04-30), and Mini Shai-Hulud on AntV (2026-05-19).
Affected versions
| Version | Note | |---|---| | 0.5.4, 0.5.5 | Adjacent pair on the 0.5 release train | | 1.6.3, 1.6.4 | Adjacent pair on the 1.6 release train | | 2.2.1, 2.2.2 | Adjacent pair on the 2.2 release train | | 3.0.3, 3.0.4 | Adjacent pair on the 3.0 release train | | 0.0.0-365d4eb738d3146583431948d3ba6e27a32556be | Commit-hash prerelease tag | | 0.0.0-ec7876d6c917dad516ba69bbfafc948b834bf0ab | Commit-hash prerelease tag |
Pairing an adjacent malicious version onto every major release train is the noteworthy detail: it catches consumers pinned to ^0.5, ^1.6, ^2.2 and ^3.0 alike, not just those tracking latest.
Root cause: unguarded issue_comment release trigger
The repository's release workflow was wired to fire on issue_comment events with types: [created] and no if: guard on the commenter. That is enough:
- Fork PR: attacker opens a pull request from a fork of
7nohe/openapi-react-query-codegencontaining an arbitrary code change (in this case, a maliciouspreinstallhook added topackage.json). - Trigger comment: the attacker leaves the comment
npm publish(or any similar keyword the workflow keys on) on that pull request. GitHub delivers anissue_commentevent; the workflow fires. - Fork checkout: the workflow checks out
github.event.pull_request.head.sha- the attacker's fork, complete with its maliciouspreinstallhook. - Preinstall runs:
pnpm install(ornpm install) executes the attacker-controlledpreinstall. Because the workflow grantedpermissions: id-token: writeat workflow scope for the trusted-publishing step, that permission is already in the environment when the preinstall runs. - Mint OIDC token: the preinstall exchanges the workflow's OIDC identity for an npm publish token via the npm trusted-publishing endpoint.
- Publish: the preinstall then invokes
npm publishten times, once for each of the poisoned versions, all landing on the legitimate@7nohe/openapi-react-query-codegenpackage identity.
The maintainer's npm credentials were never touched. The trust chain that broke is the assumption that only maintainers can trigger the workflow, and that only maintainer-authored code will ever be checked out inside it.
Payload: "Trinitite" worm
On postinstall of any consumer install, the payload:
- Reads local npm auth from
~/.npmrc,~/.config/pnpm/rc, andNPM_TOKENenvironment variables. - Reads local GitHub auth (
ghCLI cache,GH_TOKEN,GITHUB_TOKEN,~/.config/gh/hosts.yml). - Enumerates every npm package the current user has publish rights on via
npm access ls-packages. - For each such package, attempts to publish a trojanised version carrying the same worm payload - the self-propagation step.
- Creates a new attacker-controlled GitHub repository under whichever account the stolen token can reach, named
<Touhou-character-name>-<Touhou-character-name>-<random-number>with the description set literally toTrinitite: Sponsored by Preview 2 Effects. - Commits the harvested credentials to that repository as
results/doubletrinnys-{counter}-{timestamp}.json- an encrypted credential bundle plus its encryption key, mirroring the "double" naming used across earlier Shai-Hulud iterations.
Scope of downstream impact
Only @7nohe/openapi-react-query-codegen under the @7nohe scope shows the anomalous publish burst; other scoped packages did not receive suspicious publishes on 2026-08-28. Downstream: any consumer that installed a poisoned tarball between first publish and npm takedown - developer workstations and CI runners alike - must be treated as fully compromised, with every credential in reach of that environment rotated from a clean host.
Related tracked activity
- Shai-Hulud lineage: the Trinitite payload shape (harvest → self-publish → GitHub exfil) is the same family as Shai-Hulud (2025-09), Mini Shai-Hulud Wave 2 (2026-04-30), and Mini Shai-Hulud on AntV (2026-05-19); attribution circle around TeamPCP.
issue_commenttrigger abuse: the same class of unguarded workflow trigger has been used against other npm supply-chain targets (Codfish semantic-release-action GitHub Actions hijack (2026-06-24)); the pattern to look for in your own repos ison: issue_commentORon: pull_request_targetwith any write-scopepermissions:and no author-association gate.- Discovery credits: Aikido Security and SafeDep. GHSA-rg27-qr39-ch6w tracks the advisory.
Affected packages (1)
- npm@7nohe/openapi-react-query-codegen0.5.40.5.51.6.31.6.42.2.12.2.23.0.33.0.40.0.0-365d4eb738d3146583431948d3ba6e27a32556be0.0.0-ec7876d6c917dad516ba69bbfafc948b834bf0ab
These are usually pulled in as transitive dependencies rather than installed directly. Check your whole tree at once - it runs in your browser and nothing is uploaded.
Impact
- Ten malicious
@7nohe/openapi-react-query-codegenversions shipped to the npm public registry on 2026-08-28 within a ~20-minute window:0.5.4,0.5.5,1.6.3,1.6.4,2.2.1,2.2.2,3.0.3,3.0.4, plus two pre-release commit-hash tags0.0.0-365d4eb738d3146583431948d3ba6e27a32556beand0.0.0-ec7876d6c917dad516ba69bbfafc948b834bf0ab. The attacker paired each malicious release with an adjacent version across every major release train (0.5.x, 1.6.x, 2.2.x, 3.0.x) so that any consumer pinned to^0.5,^1.6,^2.2, or^3.0at install time between 2026-08-28 publish and takedown resolved a compromised tarball - The upstream package is a code generator for TanStack Query (formerly React Query) hooks against an OpenAPI schema; ~150,000 npm weekly downloads at the time of compromise. Consumers are React / TypeScript teams generating typed API clients at build time - a population that resolves the package on every
pnpm install/yarn install/npm installin CI - Attack chain: (1) attacker opened a pull request from a fork against
7nohe/openapi-react-query-codegen, (2) commentednpm publishon the PR, (3) the repository's release workflow triggered onissue_commentwithtypes: [created]fired without anif:gate ongithub.event.comment.author_association- so any GitHub user with a comment permission could invoke it, (4) the workflowcheckouted the head SHA (the attacker's fork), (5) ranpnpm installwhich executed the attacker's preinstall hook, (6) heldpermissions: id-token: writefor npm trusted publishing via OIDC, so the attacker's preinstall minted a short-lived npm publish token in-workflow, (7) used that token to publish 10 tarballs under the legitimate@7nohe/openapi-react-query-codegenidentity - Payload behaviour ("Trinitite"): on postinstall, enumerates local npm auth (
~/.npmrc,NPM_TOKEN) and every npm package the current user maintains, then attempts to publish trojanised versions of each of those packages using the harvested token - i.e. the worm self-propagates in the same shape as Shai-Hulud (2025-09) and Mini Shai-Hulud Wave 2 (2026-04-30). Exfiltrated credentials are committed to attacker-controlled GitHub repositories whose names combine two randomly-chosen Touhou Project character names plus a random number, with the repo description set literally toTrinitite: Sponsored by Preview 2 Effects, and each payload lands asresults/doubletrinnys-{counter}-{timestamp}.jsoncontaining an encrypted credential bundle and its encryption key - Impact for downstream teams: any CI or developer workstation that ran
pnpm install/yarn install/npm installfor a project pinned to any of the 10 affected versions between 2026-08-28 first publish and npm takedown should be treated as fully compromised: npm tokens, GitHub tokens surfaced in the environment, and any other secrets present in the shell / CI runner context are considered exfiltrated. If the affected machine had publish rights to other packages under the developer's npm account, those packages may already carry their own trojanised republishes - the worm shape is the whole point - Only the
@7nohe/openapi-react-query-codegenpackage under the@7nohenpm scope shows the anomalous publish burst; other packages under the same scope did not receive suspicious publishes on 2026-08-28. The maintainer's own npm credentials were not stolen - the takeover was via the CI workflow, not via account compromise
What to do
- 1Grep every lockfile (
package-lock.json,pnpm-lock.yaml,yarn.lock,bun.lock) andnode_modules/@7nohe/openapi-react-query-codegen/package.jsonfor exact versions0.5.4,0.5.5,1.6.3,1.6.4,2.2.1,2.2.2,3.0.3,3.0.4,0.0.0-365d4eb738d3146583431948d3ba6e27a32556be,0.0.0-ec7876d6c917dad516ba69bbfafc948b834bf0ab - 2Pin
@7nohe/openapi-react-query-codegento a version PUBLISHED BEFORE 2026-08-28 that you have independently verified against the upstream Git tag (a downgrade to3.0.2/2.2.0/1.6.2/0.5.3depending on your release train). Rebuild lockfiles after the pin, and re-runpnpm install --frozen-lockfile/npm cito guarantee the compromised tarball is evicted from every workspace - 3If any developer or CI runner installed one of the 10 flagged versions: treat that machine as fully compromised. Rotate every credential reachable from that machine's environment - starting with the developer's npm auth token (
npm token revoke <hash>for every token the user owns), then GitHub PATs / fine-grained tokens / SSH keys under the same user, then cloud provider CLI credentials (aws configure --profile <p>,gcloud auth login,az login), then any secret exported into the runner's environment for the affected job - 4Audit every other npm package the affected developer publishes for a trojanised republish. The worm attempts to auto-publish to every package the compromised token can reach.
npm view <pkg> versions --jsonand cross-check the latest version's publish time against the developer's intended release cadence; any version published in the same window as the compromise but not matching an expected release is suspect - 5For maintainers of any repository that uses
on: issue_commentto trigger a publish, deploy, or write-scope job: add an author-association gate immediately. Minimum viable check:if: contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association). Even better: require the comment on a PR the maintainer authored, not on any PR.pull_request_targetandissue_commentare the two most-abused triggers for supply-chain compromises via fork PRs - both need author gates AND minimalpermissions:blocks (contents: readat the top of the workflow, elevated only in the specific step that needs it) - 6For maintainers using npm trusted publishing (OIDC
id-token: write): the same author-association gate applies, and theid-token: writepermission should never be granted at the workflow level - only at the specific step that runsnpm publish. A fork checkout that runspnpm installbefore the publish step must not have any token-minting scope in its environment - 7Watch for the "Trinitite" IOCs: a new GitHub repository under any of your developers' accounts named
<Touhou-name>-<Touhou-name>-<number>with description exactlyTrinitite: Sponsored by Preview 2 Effectsand aresults/doubletrinnys-*.jsonfile is a live indicator of a compromised token in that user's environment. Delete the repo and rotate the token that could have created it - 8Anyone who previously mirrored
@7nohe/openapi-react-query-codegento an internal registry (Nexus, Artifactory, Verdaccio) must audit that mirror: internal caches routinely keep serving the poisoned tarballs after the npm public takedown. Force a re-sync from upstream once you have confirmed the malicious versions are no longer served publicly
References
- GitHubGHSA-rg27-qr39-ch6w - @7nohe/openapi-react-query-codegen (10 malicious versions, "Trinitite" worm)github.com
- AikidoPopular code generator for TanStack Query hit by supply chain wormaikido.dev
- SafeDepMini Shai-Hulud Strikes Again: openapi-react-query-codegensafedep.io
- npm@7nohe/openapi-react-query-codegen - npm registry listingnpmjs.com
- GitHub7nohe/openapi-react-query-codegen - upstream source repositorygithub.com