We found a credential-stealing worm in [email protected] . It runs on install, and npm was serving it as latest for a package with 106,000 monthly downloads.
npm records the publish at 01:12:07 UTC. SafeDep’s automated analysis flagged it at 01:20 UTC (6:50 AM IST), eight minutes later.
The payload is a new build of Mini Shai-Hulud, the 2026 wave of the Shai-Hulud worm family. It is the same worm as in the keyv and cacheable compromise .
Steals cloud, GitHub, npm, SSH, browser, and wallet credentials.
Spreads through npm packages and GitHub repositories.
Runs remote code from its command-and-control (C2) server.
Deletes the directory on some machines when someone revokes the stolen GitHub token.
npm removed the version. The maintainers reverted the source in pull request #1016 and released 0.5.145 .
What is new in this build
A hard-coded C2 domain, iseekaigogo[.]com .
A new Ethereum contract for C2 domain lookup.
A browser password stealer.
A remote code channel that runs C2 responses with eval .
A known deletion handler, rm -rf ~/ . The keyv analysis could not name it.
How the payload reached npm
The attacker did not need an npm token. They used a repository administrator account to commit the payload to main through the GitHub web interface. Then they ran the project’s own release workflow.
GitHub signs web interface commits, so all eight show as verified. The first preinstall edit broke the JSON:
The fix came 19 minutes later. This suggests a person who edited files in a browser (inference).
On 8 October at 00:08 UTC, the account started publish_npm.yaml by hand. The build log shows the payload files in the tarball:
The release used npm trusted publishing.
The sibling tensorlake-native-*@0.5.144 packages carry valid SLSA provenance for this run. The provenance is valid for a build of poisoned source.
The preinstall hook ran in this job and ended in 0.1 seconds. The loader skips CI, so the payload probably did not run on the runner (inference).
The shipped lib/setup.mjs uses RC4 string obfuscation. The worm carries a plain copy of it, which it plants in other packages and repositories:
It downloads Bun 1.3.13 from the official GitHub release.
It runs Math_Symbol.js with Bun.
It exits on CI runners.
The shipped setup.mjs decodes to the same strings.
lib/Math_Symbol.js is 856,501 bytes. Its first line names the build:
Three layers hide the code:
An obfuscator string array hides identifiers.
A custom cipher hides configuration strings. It uses salt svksjrhjkcejg , the same as keyv.
AES-256-GCM hides eleven embedded files, including scripts, hooks, and two RSA public keys.
All layers decode without running the sample. An earlier 849,332-byte build in the commit history has the same configuration.
Snippets below are deobfuscated and keep the original identifiers.
The worm posts data to hxxps://iseekaigogo[.]com:443/router . If that fails, it tries:
Ethereum. It reads contract 0xb614155Fd88114d40549b259457Bcf921Df091B9 through 35 public RPC endpoints. On 8 October the contract returned iseekaigogo.com .
Signed GitHub commits. It searches for thebeautifulmarchoftime and trusts only commits signed with an embedded RSA key.
Dead-drop repositories. It commits encrypted data to new public repositories with the description Shai-Hulud: Here We Go Again .
Every C2 response can carry code. The worm runs it:
After exfiltration, the worm pings the C2 every 45 to 90 seconds and runs any code it gets back.
The browser binary runs as dump -b all -c password -f json . These arguments match HackBrowserData (inference, the binary was not recovered). The worm exits on Russian locales.
The watcher arms only for stolen tokens whose account has no organizations:
gh-token-monitor checks the token every 60 seconds for 24 hours.
If GitHub returns 40x, for example after revocation, it deletes the directory.
It runs as a systemd user service, a macOS LaunchAgent, or a Windows scheduled task.
Remove gh-token-monitor before you revoke GitHub tokens.
npm tokens. It adds the payload and preinstall to every package the token can publish, bumps the patch version, and publishes.
npm trusted publishing. In CI, it adds a git dependency and signs the package with Fulcio and Rekor.
GitHub tokens. It commits Claude Code and VS Code hooks as author claude . It also plants a Run Copilot workflow that dumps all repository secrets, then deletes the run and branch.
The hook files and workflow match the keyv post . See also configuration files that run code .
Two bugs in the code may limit spread:
The npm path needs ./dist/Math_Symbol.js on disk and stops without it.
The planted loader looks for ai_init.js , but the worm writes math_init.js .
Indicators of compromise
tensorlakeai/tensorlake pull request #1016
Release workflow run 37706134202
Payload commit 41b38f09
keyv and cacheable npm compromise
Inside the Miasma supply chain attack toolkit
The Latest from SafeDep blogs
Follow for the latest updates and insights on open source security & engineering
One RubyGems account published 42 gems that run code during gem install. On a developer workstation, the gems open a reverse shell or download a second stage. They do nothing on CI runners and...
A malicious pull request against oxc led SafeDep to a larger campaign. The PolinRider loader family now reads its C2 servers from Ethereum transactions. SafeDep confirmed 35 GitHub repositories that...
An attacker took over a live AI coding assistant session, got it to recommend a poisoned package, and used the stolen tokens to spread the Shai-Hulud worm across 100 internal repositories.
Nine fake Express and React packages on npm run a Linux worm at install time. It installs a Tor backdoor and spreads through SSH, AUR packages, and npm tokens.
Start free with open source tools on your machine. Scale to a unified platform for your organization.
The full story
This article is one source in a clustered incident — the cluster page carries the summary, timeline and every other outlet covering it.
