A new Shai-Hulud supply-chain campaign, tracked as Trinitite, has compromised the npm package @7nohe/openapi-react-query-codegen, which receives more than 150,000 weekly downloads.
The malicious versions use a hidden binding.gyp execution path and a large obfuscated JavaScript loader to infect developer machines and CI environments.
The campaign appears linked to the previously reported Shai-Hulud “Mini” worm family, including the Here We Go Again, May 19, and Miasma waves.
Researchers said the latest operation uses the same core malware capabilities but changes its publishing method, campaign strings, encryption keys, and install-time execution technique.
The compromised package release workflow reportedly accepted a pull-request comment containing npm publish as a publishing trigger. It then checked out the pull request and published the package through GitHub Actions OpenID Connect (OIDC), without confirming that the commenter was a maintainer.
This allowed attacker-controlled code to receive a valid trusted-publishing token.
As a result, the malicious versions show legitimate npm provenance, although the provenance only proves that the repository’s automated publishing workflow ran not that the published code was safe.
The attackers first released two prerelease versions. One of them included a preinstall command that installed Bun and attempted to execute a missing file named is_it_this_simple.js.
It did not contain the full worm, but its environment variables already referenced the later infection workflow.
Shai-Hulud Worm Hits npm
Eight stable package versions later introduced the main payload. The first wave used binding.gyp, while a second wave added a visible preinstall hook that ran node 3FWCvzduYZg.js.
The 3FWCvzduYZg.js file is a 4–6 MB XOR-obfuscated loader. It decrypts and executes a larger Shai-Hulud worm through Bun, then deletes the temporary JavaScript payload.
If Bun is unavailable, the loader downloads the legitimate Bun binary from GitHub and stores it in a temporary directory.
The notable technique is the malicious binding.gyp file. Its Unicode-escaped Python condition eventually executes:
os.system('node 3FWCvzduYZg.js')
Because node-gyp can evaluate binding.gyp conditions during installation, simply using --ignore-scripts may not prevent execution. This lets the malware bypass security controls that only inspect package.json lifecycle scripts.
Once active, Trinitite can steal GitHub, npm, PyPI, RubyGems, cloud, Kubernetes, Vault, SSH, and CI credentials.
It also searches GitHub runner memory for secrets, creates malicious GitHub Actions workflows, and republishes packages where stolen tokens provide write access.
Affected versions include 0.5.4, 0.5.5, 1.6.3, 1.6.4, 2.2.1, 2.2.2, 3.0.3, and 3.0.4. Safe versions are 0.5.3, 1.6.2, 2.2.0, and 3.0.2.
Organizations should isolate any endpoint or CI runner that installed an affected version. Security teams should hunt for 3FWCvzduYZg.js, binding.gyp, trinnyyyy-* directories, /var/tmp/.shit, and ~/.local/share/diaper/poopy.py, jfrog said.
Indicators of Compromise
| IOC Type | Indicator | Notes |
|---|---|---|
| Compromised npm package | @7nohe/openapi-react-query-codegen | Package affected by the Trinitite/Shai-Hulud campaign |
| Malicious package 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 | Stable versions carrying the worm |
Note: IP addresses and domains are intentionally defanged (e.g., [.]) to prevent accidental resolution or hyperlinking. Re-fang only within controlled threat intelligence platforms such as MISP, VirusTotal, or your SIEM.
Detect, investigate, and respond faster with in-browser data inspection from ANY.RUN-> Power your SOC with ANY.RUN