Mini Shai-Hulud Supply-Chain Attack Compromises 10 npm Package Versions

· Original article ↗

Summary

Ten malicious versions of @7nohe/openapi-react-query-codegen were published through an abused GitHub Actions workflow. The package’s install-time payload steals credentials and can propagate through developer and CI environments.

Key points

  • Ten versions published on August 28, 2026, remain installable; the latest tag points to compromised version 3.0.4. Last known-good releases are 0.5.3, 1.6.2, 2.2.0, and 3.0.2.
  • An issue-comment workflow allowed untrusted users to publish code from a pull-request fork by commenting “npm publish”; the job used GitHub Actions trusted publishing.
  • The malicious package executes an obfuscated payload during installation, using a binding.gyp build trigger and, in some versions, a preinstall script.
  • The payload searches files, process memory, cloud metadata, and CI variables for credentials, then can exfiltrate data and abuse package-registry and GitHub permissions.
  • Additional capabilities include CI workflow tampering, developer-tool persistence, SSH propagation, and monitoring for GitHub tokens.
  • Valid npm provenance attestations did not ensure the published tarballs contained trusted code; npm audit signatures may not flag these versions.
  • Socket advises isolating affected systems, addressing persistence, rotating exposed credentials, checking for affected versions, and pinning to a known-good release.

Article Details

Attack Vectors
  • An untrusted GitHub account could comment `npm publish` on a pull request to trigger a publishing workflow that checked out the fork's code without checking the commenter's repository association.
  • The workflow published attacker-modified versions of @7nohe/openapi-react-query-codegen through GitHub Actions trusted publishing, giving all ten malicious releases valid npm provenance attestations.
  • Installation of the affected releases executed an obfuscated JavaScript loader through binding.gyp; later releases also used a preinstall script. The two malicious prereleases used separate preinstall paths.
  • The decrypted payload contains credential discovery and validation, encrypted exfiltration to attacker-created public GitHub repositories, package poisoning, GitHub Actions workflow modification, developer-tool configuration persistence, and SSH propagation. The reported analysis was based on static inspection; the payload was not executed by the researchers.
Defensive Notes
  • Isolate systems and CI runners that installed an affected version. Prefer rebuilding from a known-clean image and check for persistence before rotating exposed credentials.
  • Contain the host and disable the reported GitHub-token monitor before revoking or testing its token: an HTTP 400–409 response can cause the monitor to evaluate its stored handler.
  • Pin @7nohe/openapi-react-query-codegen to a last known-good version—0.5.3, 1.6.2, 2.2.0, or 3.0.2—and reinstall from a clean lockfile after clearing package-manager caches and existing node_modules.
  • Check lockfiles and SBOMs for all ten affected versions, including transitive installations. Do not rely on npm audit signatures or valid provenance attestations to identify these releases.
  • Review GitHub audit logs, package-registry publishing activity, the reported persistence paths, developer-tool configurations, and SSH logs for follow-on activity.
  • Maintainers should verify commenter repository association before allowing an issue_comment-triggered publishing job with id-token: write, or use a trigger that an untrusted account cannot invoke.

Indicators of compromise

TypeIndicatorContext
SHA25659370c67b54a0ccaedd265e2356f04540b2fba1e1845300ef6de4d5437d99380Hash listed for the malicious 3FWCvzduYZg.js loader.
SHA256b49afb7dba04cd99b357ce7c652c823a3707f28e130bd5c6645851a7adc030d6Hash listed for the malicious 3FWCvzduYZg.js loader.
SHA256d3246926b20a8d021ed7de0ac8e9eee1dda986088f84ba18f31cb2042a121f5dHash listed for the malicious binding.gyp build trigger.

MITRE ATT&CK

T1021.004 · SSHThe recovered propagator uses SSH and scp to copy scripts to reachable hosts and run the implant remotely.T1027 · Obfuscated Files or InformationThe installation loader uses single-byte XOR obfuscation, while the binding.gyp command is concealed with Unicode escapes.T1059.006 · PythonThe binding.gyp condition uses a Python expression to invoke os.system, and the recovered payload uses Python modules for memory reading and command execution.T1059.007 · JavaScriptInstallation runs the malicious JavaScript loader with node; the loader decrypts and executes a second-stage payload.T1102.001 · Dead Drop ResolverThe recovered harvester searches GitHub commits for signed messages containing a URL from which it downloads and executes a Python command.T1195.001 · Compromise Software Dependencies and Development ToolsThe actor published malicious versions of @7nohe/openapi-react-query-codegen and the recovered payload contains functionality to poison other writable packages.T1528 · Steal Application Access TokenThe payload seeks GitHub, npm, and other application tokens in files, process memory, and environment variables, then validates them for reuse.T1543.001 · Launch AgentOn macOS, the token-monitor installer creates and bootstraps a persistent LaunchAgent with RunAtLoad and KeepAlive.T1543.002 · Systemd ServiceOn Linux, the token-monitor installer creates and enables a persistent user systemd service.T1552.001 · Credentials In FilesThe payload recursively scans files, including dotfiles, for tokens and other secrets.T1552.005 · Cloud Instance Metadata APICloud-provider modules query instance metadata endpoints to obtain credentials.T1567.001 · Exfiltration to Code RepositoryA recovered module creates public GitHub repositories and commits encrypted collections of stolen findings to them.

Vendors

Products

Related Articles