DEV Community

jamilxt
jamilxt

Posted on

The Shai-Hulud Worm Now Steals Your AI Agent Credentials: A 20-Minute npm Audit

The most dangerous part of this attack is not the stealing. It is the trap that fires when you do the right thing.

Last week a malicious version of the Tensorlake npm SDK went out with a worm inside it. It harvested GitHub and npm tokens, cloud keys, SSH keys, and the config files of AI coding tools. Then it installed a small background service that checked, every 60 seconds, whether the stolen GitHub token still worked. If you revoked the token, the service ran rm -rf ~/ on your machine. Security researchers started calling it the hostage token, and the name is not an exaggeration. The malware source contains the literal string IfYouRevokeThisTokenItWillWipeTheComputerOfTheOwner.

If you installed one specific package in a specific 24-hour window, your first instinct, revoking your tokens, is exactly what sets off the destructive payload. The order of operations matters here, and that is what this article is for: how to check whether you are exposed, what to remove before you rotate anything, and what to change so the next wave of this worm finds nothing to steal.

Full disclosure: I use AI coding agents daily, and I did not investigate this incident myself. Everything below comes from StepSecurity's teardown of the payload, Socket's analysis, Tensorlake's own security advisory, and coverage in The Register, all linked inline. Where I am giving an opinion instead of a sourced fact, I say so.

What happened, in order

Tensorlake builds sandboxed infrastructure for running AI-generated code, and its npm SDK had around 12,000 weekly downloads and more than 1,000 GitHub stars. Here is the timeline, from StepSecurity's report:

  • October 7, 01:20 UTC. The first malicious commit landed on the main branch of the Tensorlake repo, under a maintainer's name. Seven more commits followed over the next few hours. None went through a pull request.
  • October 8, 01:12 UTC. The repo's own release workflow published version 0.5.144 to npm. Because the package was built from the project's real repository by the project's real workflow, npm showed a valid provenance attestation for it.
  • October 8, 01:23 UTC. Socket flagged the release, about 11 minutes after publication. Detection was fast. Whether that was fast enough depends entirely on when you ran npm install.

The attack path is worth pausing on. The attacker did not hijack a random maintainer's laptop or forge a package. Per Snyk's analysis, someone used a repository administrator account to push the payload directly to main through the GitHub web interface, then let the project's legitimate release automation publish it. The provenance attestation says where a package was built. It says nothing about whether the code is safe, and this incident is now the clearest example of that difference you will find.

When you install the package, a preinstall hook runs. It skips CI environments and targets developer machines, downloads the Bun runtime, and uses it to execute an obfuscated 856 KB JavaScript file. From there, it collects:

  • Package registry tokens: npm tokens from .npmrc files and the npm token API, plus OIDC token exchange material.
  • Source control tokens: GitHub tokens, which it checks for repository and workflow permissions.
  • Cloud credentials: AWS credentials from the Instance Metadata Service, ECS, Secrets Manager, and Systems Manager Parameter Store.
  • Infrastructure secrets: HashiCorp Vault data from local instances, Kubernetes service-account tokens, and kubeconfig files.
  • Everything else on disk that looks valuable: SSH keys, .env files, cryptocurrency wallets, saved browser logins, and messaging app data.
  • Your AI agent's brain: configuration and MCP files from .claude, .cursor, .kiro, Windsurf, and Zed.

That last item is the part that should bother anyone running AI coding agents. Your .claude folder and your MCP configuration files are not just preferences. They contain API keys, the list of servers your agents can call, and in many setups, credentials for those servers. A worm that steals them does not just get access to your accounts. It gets a map of every automated credential path on your machine, written down in one convenient place.

Exfiltrated data is encrypted and sent to one of two places: a public GitHub repository created in the victim's own account, described as "Shai-Hulud: Here We Go Again", or the domain iseekaigogo.com. The command-and-control address is not hardcoded anywhere. Per Socket, the payload resolves its endpoint by reading an Ethereum contract through roughly 30 public RPC endpoints, with a GitHub fallback. Takedown requests are nearly useless against that design.

How it spreads, and why it wears your clothes

With a stolen npm token, the worm downloads the victim's own packages, adds itself, bumps the version, and republishes them, generating valid-looking Sigstore provenance as it goes. With a stolen GitHub token, it commits files into the victim's repositories: .claude/settings.json and .vscode/tasks.json that re-run the payload when someone opens the project in Claude Code or VS Code. Those commits are authored by claude@users.noreply.github.com with the message "chore: update dependencies".

Read that again if you skimmed it. The worm hides inside commits that look exactly like the AI-assisted commits your team produces every day. An unfamiliar commit from a Claude noreply address updating dependencies is not going to raise an eyebrow on most projects in 2026. That is a genuinely nasty piece of social engineering built on top of a credential stealer, and I expect copycats to reuse it even after this particular campaign dies.

This is also the second Shai-Hulud campaign this year. Socket matches the structure of the payload, a setup.mjs loader running an obfuscated Math_Symbol.js file, to the August compromises of the keyv and cacheable packages. The technique is a recipe now, and recipes get replayed against whatever dependency has a weak point that week.

The audit, in the right order

Tensorlake's advisory tells anyone affected to pin version 0.5.143 and rotate credentials. StepSecurity's teardown adds the step most people would miss: neutralize the token monitor before you revoke anything. Follow the steps in this order. Do not skip to the token revocation.

Step 1: Find out whether you have it. Run npm ls tensorlake in your projects, and search your lockfiles for 0.5.144:

grep -r "tensorlake" package-lock.json yarn.lock pnpm-lock.yaml 2>/dev/null
grep -rn "tensorlake@0.5.144" . --include="*lock*"
Enter fullscreen mode Exit fullscreen mode

Also check whether you cloned or pulled the Tensorlake repo's main branch since October 7 and ran npm install inside its typescript/ directory. The malicious code lived on main, not just in the npm tarball.

Step 2: Back up anything you cannot lose. Before touching the persistence mechanism, copy your work somewhere off-machine. One of the payloads you are about to disconnect has a history of deleting home directories, and a mistake during cleanup should never be the thing that costs you your files.

Step 3: Remove the token monitor, if it exists. Look for ~/.config/gh-token-monitor/. On Linux, StepSecurity gives this cleanup:

systemctl --user disable --now gh-token-monitor.service
rm -rf ~/.config/gh-token-monitor ~/.local/bin/gh-token-monitor.sh ~/.config/systemd/user/gh-token-monitor.service
Enter fullscreen mode Exit fullscreen mode

On macOS:

launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.user.gh-token-monitor.plist
rm -rf ~/.config/gh-token-monitor ~/.local/bin/gh-token-monitor.sh ~/Library/LaunchAgents/com.user.gh-token-monitor.plist
Enter fullscreen mode Exit fullscreen mode

On Windows, check Task Scheduler for a logon task running a monitor.ps1 script and delete it. The Linux variant polls every 60 seconds for up to 24 hours. The Windows variant uses an ONLOGON scheduled task and a PowerShell monitor.

Step 4: Now rotate everything. Only after the monitor is gone is it safe to revoke the GitHub token. Then work through the rest, and note that the AI tool entries at the end of this list are new compared to every prior npm incident I have read:

  • npm tokens and GitHub personal access tokens
  • AWS credentials, plus anything in Secrets Manager or Parameter Store that the machine could reach
  • Kubernetes service-account tokens and kubeconfig contents
  • Vault credentials
  • SSH keys
  • Secrets in .env files
  • API keys stored in .claude, .cursor, Windsurf, Zed, and .kiro configs, and credentials for any MCP servers those configs reference
  • Passwords saved in your browser

Step 5: Check whether it already spread. On your GitHub account, look for new public repos with the "Shai-Hulud" description, commits authored by claude@users.noreply.github.com, and .claude or .vscode files you did not add. In your npm account, check for package versions you did not publish. Tensorlake's advisory adds a detail worth remembering: check CI logs for any install that resolved to 0.5.144 between 01:12 and 02:54 UTC on October 8.

Step 6: If you are not sure the machine is clean, wipe it. Both Socket and StepSecurity say the same thing: removing the npm dependency does not remove a persistent implant. Rebuild from a trusted image.

One scope note, because it matters: the preinstall hook skips CI environments. If the package only ever ran in CI, your exposure is different, though the secrets that job could see should still be rotated.

Making the next one boring

The audit tells you whether this wave hit you. These changes reduce the blast radius of the next one, and none of them require new tooling.

Disable install scripts by default. Put this in your .npmrc:

ignore-scripts=true
Enter fullscreen mode Exit fullscreen mode

Most packages do not need lifecycle hooks to work, and the ones that do will fail loudly, at which point you make a conscious decision instead of a default one. This single line would have stopped the Tensorlake payload and most of the npm malware campaigns of the past two years at the install step.

Pin your versions and read the diff. A lockfile that floats on version ranges will happily pull a poisoned release in the first minute of its publish window. Pin what you deploy, and when an update arrives, the lockfile diff should be part of your review, not an invisible artifact.

Treat AI agent configs as credential stores. They are. Audit what is actually in your .claude and .cursor directories and your MCP configurations. Keys that are only needed by a remote server do not belong in files that a local install script can read. If an MCP server has its own scoped token, the blast radius of stealing that file is one revocation instead of your whole machine.

Scope tokens tightly and expire them. The worm graded the GitHub tokens it stole by repository and workflow permissions before deciding what to do with them. A token that can only read the repos it needs makes that grading step much less rewarding. Classic tokens with broad scopes and no expiry are the worst case, and a lot of us still have them.

Wait before adopting fresh releases. Socket flagged this package 11 minutes after publication, which is genuinely fast, but 11 minutes is also enough time for a hundred npm install runs. A cooldown of a day or two on new versions of critical dependencies costs you almost nothing and filters out most rapid-response takedowns of exactly this kind. This is my opinion rather than a sourced best practice, but the math has held up across several incidents now.

The part that generalizes

The credential theft itself is not new. What is new is the target list, and it says something about where attackers think the value has moved. The worm reads your AI tool configs for the same reason it reads your .npmrc: that is where the working credentials live. As agents get more autonomy, more integrations, and more long-lived tokens, the config folder becomes a higher-value target than the code.

The uncomfortable implication is that your agent's tool supply chain is now part of your threat model whether you agreed to that or not. Every MCP server your agent calls is remote code your agent executes. Every config file that lists those servers is a document worth stealing. None of the mainstream agent tooling treats this with the seriousness it now deserves, and the OX Security research on public MCP servers from earlier this month suggests the wider ecosystem has the same gap.

Start with the audit. It takes 20 minutes, and given that step 3 exists, "I'll rotate my tokens later" is not a plan.


I write about developer tools, security, and AI infrastructure every week. Subscribe, it is free.

Have you audited your own AI agent configs since this campaign started? What did you find that surprised you?

Top comments (0)