# Trinitite worm compromises @7nohe/openapi-react-query-codegen on npm

> 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.

- Published: 2026-08-28
- Last updated: 2026-08-29
- Severity: critical
- Kind: Compromise - A legitimate, already-used package, maintainer account, CI pipeline, or release tag was hijacked and a malicious version was published under a name people already depend on.
- Ecosystems: npm
- Scope: 1 package, 10 compromised versions
- Tags: worm, credential-theft, ci-cd-compromise, account-takeover, maintainer-takeover
- Threat actor: TeamPCP (attributed) - "Trinitite" campaign
- 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
- Detected by: Aikido Security, SafeDep, GitHub Advisory Database
- Incident ID: npm-2026-08-28-trinitite-openapi-react-query-codegen

## Affected packages (1)

Only the exact versions listed were named by the source advisories. Other versions are not implicated.

| Package | Ecosystem | Compromised versions |
|---|---|---|
| [@7nohe/openapi-react-query-codegen](https://dependencywatch.io/package/npm/@7nohe/openapi-react-query-codegen) | npm | 0.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 |

## 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)](https://dependencywatch.io/incident/npm-2025-09-shai-hulud-original), [Mini Shai-Hulud Wave 2 (2026-04-30)](https://dependencywatch.io/incident/multi-2026-04-30-mini-shai-hulud-wave2), and [Mini Shai-Hulud on AntV (2026-05-19)](https://dependencywatch.io/incident/npm-2026-05-19-antv-mini-shai-hulud).

## 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:

1. **Fork PR**: attacker opens a pull request from a fork of `7nohe/openapi-react-query-codegen` containing an arbitrary code change (in this case, a malicious `preinstall` hook added to `package.json`).
2. **Trigger comment**: the attacker leaves the comment `npm publish` (or any similar keyword the workflow keys on) on that pull request. GitHub delivers an `issue_comment` event; the workflow fires.
3. **Fork checkout**: the workflow checks out `github.event.pull_request.head.sha` - the attacker's fork, complete with its malicious `preinstall` hook.
4. **Preinstall runs**: `pnpm install` (or `npm install`) executes the attacker-controlled `preinstall`. Because the workflow granted `permissions: id-token: write` at workflow scope for the trusted-publishing step, that permission is already in the environment when the preinstall runs.
5. **Mint OIDC token**: the preinstall exchanges the workflow's OIDC identity for an npm publish token via the npm trusted-publishing endpoint.
6. **Publish**: the preinstall then invokes `npm publish` ten times, once for each of the poisoned versions, all landing on the legitimate `@7nohe/openapi-react-query-codegen` package 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`, and `NPM_TOKEN` environment variables.
- Reads local GitHub auth (`gh` CLI 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 to `Trinitite: 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)](https://dependencywatch.io/incident/npm-2025-09-shai-hulud-original), [Mini Shai-Hulud Wave 2 (2026-04-30)](https://dependencywatch.io/incident/multi-2026-04-30-mini-shai-hulud-wave2), and [Mini Shai-Hulud on AntV (2026-05-19)](https://dependencywatch.io/incident/npm-2026-05-19-antv-mini-shai-hulud); attribution circle around **TeamPCP**.
- **`issue_comment` trigger 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)](https://dependencywatch.io/incident/github-actions-2026-06-24-codfish-semantic-release-action-hijack)); the pattern to look for in your own repos is `on: issue_comment` OR `on: pull_request_target` with any write-scope `permissions:` and no author-association gate.
- Discovery credits: **Aikido Security** and **SafeDep**. GHSA-rg27-qr39-ch6w tracks the advisory.

## Impact

- Ten malicious `@7nohe/openapi-react-query-codegen` versions 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 tags `0.0.0-365d4eb738d3146583431948d3ba6e27a32556be` and `0.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.0` at 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 install` in CI
- **Attack chain**: (1) attacker opened a pull request from a fork against `7nohe/openapi-react-query-codegen`, (2) commented `npm publish` on the PR, (3) the repository's release workflow triggered on `issue_comment` with `types: [created]` fired **without an `if:` gate on `github.event.comment.author_association`** - so any GitHub user with a comment permission could invoke it, (4) the workflow `checkout`ed the head SHA (the attacker's fork), (5) ran `pnpm install` which executed the attacker's preinstall hook, (6) held `permissions: id-token: write` for 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-codegen` identity
- **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)](https://dependencywatch.io/incident/npm-2025-09-shai-hulud-original) and [Mini Shai-Hulud Wave 2 (2026-04-30)](https://dependencywatch.io/incident/multi-2026-04-30-mini-shai-hulud-wave2). 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 to `Trinitite: Sponsored by Preview 2 Effects`, and each payload lands as `results/doubletrinnys-{counter}-{timestamp}.json` containing an encrypted credential bundle and its encryption key
- **Impact for downstream teams**: any CI or developer workstation that ran `pnpm install` / `yarn install` / `npm install` for 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-codegen` package under the `@7nohe` npm 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

1. Grep every lockfile (`package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`, `bun.lock`) and `node_modules/@7nohe/openapi-react-query-codegen/package.json` for exact versions `0.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`
2. Pin `@7nohe/openapi-react-query-codegen` to a version PUBLISHED BEFORE 2026-08-28 that you have independently verified against the upstream Git tag (a downgrade to `3.0.2` / `2.2.0` / `1.6.2` / `0.5.3` depending on your release train). Rebuild lockfiles after the pin, and re-run `pnpm install --frozen-lockfile` / `npm ci` to guarantee the compromised tarball is evicted from every workspace
3. **If 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
4. **Audit 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 --json` and 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
5. **For maintainers of any repository that uses `on: issue_comment` to 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_target` and `issue_comment` are the two most-abused triggers for supply-chain compromises via fork PRs - both need author gates AND minimal `permissions:` blocks (`contents: read` at the top of the workflow, elevated only in the specific step that needs it)
6. **For maintainers using npm trusted publishing (OIDC `id-token: write`)**: the same author-association gate applies, and the `id-token: write` permission should never be granted at the workflow level - only at the specific step that runs `npm publish`. A fork checkout that runs `pnpm install` before the publish step must not have any token-minting scope in its environment
7. **Watch for the "Trinitite" IOCs**: a new GitHub repository under any of your developers' accounts named `<Touhou-name>-<Touhou-name>-<number>` with description exactly `Trinitite: Sponsored by Preview 2 Effects` and a `results/doubletrinnys-*.json` file 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
8. Anyone who previously mirrored `@7nohe/openapi-react-query-codegen` to 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

## Check your own dependencies

- Check a package-lock.json against this incident: https://dependencywatch.io/check/package-lock-json

The scan runs entirely in the browser; lockfile contents are never uploaded.

## References

- [GHSA-rg27-qr39-ch6w - @7nohe/openapi-react-query-codegen (10 malicious versions, "Trinitite" worm)](https://github.com/advisories/GHSA-rg27-qr39-ch6w) - GitHub
- [Popular code generator for TanStack Query hit by supply chain worm](https://www.aikido.dev/blog/popular-code-generator-for-tanstack-query-hit-by-supply-chain-worm) - Aikido
- [Mini Shai-Hulud Strikes Again: openapi-react-query-codegen](https://safedep.io/mini-shai-hulud-openapi-react-query-codegen-compromised/) - SafeDep
- [@7nohe/openapi-react-query-codegen - npm registry listing](https://www.npmjs.com/package/@7nohe/openapi-react-query-codegen) - npm
- [7nohe/openapi-react-query-codegen - upstream source repository](https://github.com/7nohe/openapi-react-query-codegen) - GitHub

---

Canonical page: https://dependencywatch.io/incident/npm-2026-08-28-trinitite-openapi-react-query-codegen
Markdown version: https://dependencywatch.io/incident/npm-2026-08-28-trinitite-openapi-react-query-codegen.md
Site index for agents: https://dependencywatch.io/llms.txt
DependencyWatch.io is operated by Precursor Security (https://precursorsecurity.com).
