Skip to content
System nominalUTC --:--:--Articles 080
Security 7 min read

The tensorlake npm Worm Targets AI Tools, and Waits for a Token Revoke

Version 0.5.144 of the tensorlake npm SDK shipped a preinstall worm that wipes the machine if a stolen GitHub token is revoked.

Cover graphic for: The tensorlake npm Worm Targets AI Tools, and Waits for a Token Revoke

If a host in your fleet installed tensorlake@0.5.144, the first action is not to rotate the GitHub token the package stole. The payload installs a monitor that polls GitHub with that token, and if it sees the token revoked while the monitor is still running, it runs an attacker-supplied handler that destroys data on the machine. Socket's advisory for the compromise and the Cloud Security Alliance research note both put persistence removal ahead of credential revocation, and the order is the difference between a cleanup and a wiped machine.

Revoking is the reflex, and it is the wrong first move here.

What shipped, and how fast it was caught

Version 0.5.144 of the tensorlake npm package, the TypeScript SDK for an agent-sandbox platform, was published to the registry on 8 October 2026 at 01:12:07 UTC. Socket's automated scanning flagged it at 01:23:10, roughly eleven minutes later, and the version was removed from npm the same day. Vendors attribute the payload to the Shai-Hulud npm worm family and to a campaign they call ChainDrop.

The package is not large in download terms. Socket reports around 12,000 weekly downloads and more than 1,000 GitHub stars. The size is not the exposure. An SDK for agent sandboxes is installed by developers and build systems that hold cloud credentials, model provider keys and repository publishing rights in the same environment, which is exactly the profile a credential-harvesting worm is built for.

The install hook runs before your code does

The manifest added a preinstall script that runs node lib/setup.mjs. Socket describes that file as an obfuscated loader that launches the main payload, lib/Math_Symbol.js, using the Bun runtime. Endor Labs puts the payload at around 856KB and reports that it contains a worm marker string.

Because it fires from a lifecycle hook, the payload runs on every machine or CI job that resolves the compromised version, including transitive installs where no developer ever imported the SDK. There is no import statement to review and no application code to read first.

The collection list is broad. Socket and Endor Labs describe npm tokens and OIDC exchanges, GitHub tokens and CLI configuration, AWS credentials from instance metadata, ECS, Secrets Manager and SSM, other cloud provider credentials, HashiCorp Vault tokens, Kubernetes service accounts, Docker configuration, SSH keys, .env files and cryptocurrency wallets. Both Socket and The Hacker News add configuration files for AI coding tools, naming Claude, Cursor and Zed. Other reports extend the list to Windsurf, Kiro and VS Code, and those lists do not match each other. On CI runners, Endor Labs reports that the payload checks environment variables such as CI and GITHUB_ACTIONS and downloads a second stage.

For an agent platform the practical consequence is that model provider keys, MCP server tokens and agent configuration sit in the same directories as the cloud and registry credentials the worm already hunts for. One install reaches all of them.

Remove persistence before you revoke anything

According to Socket, the payload installs a PowerShell-based monitor through an on-logon scheduled task. The monitor polls GitHub's API with the stolen token to detect revocation. If revocation is detected, an attacker-supplied handler executes through Invoke-Expression, and the code contains a literal string warning that revoking the token will wipe the owner's computer. The Hacker News describes the destructive action as wiping the home directory.

Socket's remediation guidance for Windows, Linux and macOS therefore lists removal of the persistence mechanism as a step that comes before credential revocation: delete the scheduled task on Windows, disable the service on Linux, remove the LaunchAgent on macOS. Preserve a forensic copy of the mechanism where you can, then revoke.

# 1. Find the persistence first. Do not revoke any token yet.
systemctl list-units --type=service --all | grep -iE 'node|bun|tensorlake'
systemctl list-timers --all
ls -la ~/Library/LaunchAgents
launchctl list | grep -iE 'tensorlake|node|bun'

# 2. Only after persistence is gone, find what installed it.
grep -rn 'tensorlake' package.json package-lock.json pnpm-lock.yaml yarn.lock 2>/dev/null
# Windows: enumerate scheduled tasks and inspect anything with a logon trigger.
schtasks /query /fo LIST /v | findstr /i "logon"
Get-ScheduledTask | Select-Object TaskName, TaskPath, State

Removing the dependency does not remove the foothold. The Hacker News reports that the malware writes .claude/settings.json and .vscode/tasks.json files into repositories, which lets tool and editor configuration re-run attacker commands after the npm package is gone. Socket notes references to fake Copilot and Dependabot workflows, which suggests the ability to inject GitHub Actions workflows. Any repository the affected machine could write to needs those file types reviewed, along with unexpected workflow files.

Valid provenance, poisoned source

The release carried valid Sigstore provenance. Endor Labs attributes that to the order of events: the malicious change was committed to the source repository before the project's trusted build pipeline ran. The attestation correctly recorded that the artifact was built from the repository, and the repository was already compromised.

The likely root cause in the reporting is control of a maintainer's GitHub identity. The attacker pushed commits that appeared verified and landed on the main branch. How that access was obtained is not established by any of the sources. What the incident does establish is the limit of attestation as a trust signal. It answers where a build came from, not whether the source it came from was clean. Branch protection, a required second reviewer for changes to release workflows and manifests, and phishing-resistant authentication on maintainer accounts address that gap more directly than an attestation check.

The vendors do not agree on the details

Three points in the public record are contested, and the differences are worth stating rather than averaging out.

On timing, Aikido describes the gap between the first malicious commit and the npm publication as roughly twenty hours, while the timestamps in other reports imply closer to twenty-four. The reports do not explain the difference, and Aikido and Endor Labs cite different commit identifiers for the first malicious change. The Cloud Security Alliance note declines to reproduce either identifier for that reason. The dates that are consistent across sources are the ones below: a command-and-control address written to an Ethereum contract on 21 September, the first malicious commit on 7 October at around 01:20 UTC, the npm publication on 8 October at 01:12:07, and Socket's flag at 01:23:10.

On command and control, Socket reports that the payload contains no hardcoded domains and resolves endpoints through roughly thirty public Ethereum RPC endpoints with a GitHub fallback. Aikido names a primary domain, iseekaigogo[.]com, alongside the Ethereum contract. The Hacker News lists an additional exfiltration endpoint on a domain registered for the campaign. The three descriptions are not compatible with a single simple architecture, and blocking one domain is unlikely to interrupt the malware on its own.

On which AI tool configurations were targeted, sources list Claude, Cursor and Zed, and then some combination of Windsurf, Kiro and VS Code depending on who you read. Treat the short list as confirmed and the longer one as reported.

One more gap matters for anyone assessing the blast radius. No statement from Tensorlake or its maintainers appears in any of the sources, so there is no vendor account of which build systems resolved the poisoned version. Aikido reports that only the npm package was affected as of its write-up, with no corresponding compromise found in the Python distribution. That is a negative finding from one vendor on one day, not a clearance, and it should be re-checked against current advisories.

What to do, in order

Search lockfiles, dependency manifests, build caches and container images for tensorlake@0.5.144, and block the version in internal registries and proxies. Endor Labs advises pinning to 0.5.143 and purging references to 0.5.144 from lockfiles. Any host or CI job that installed the version should be treated as fully compromised and isolated before remediation starts.

Then, on each affected host, remove the persistence mechanism and keep a forensic copy where feasible. Only after that revoke and rotate the exposed credentials: npm, GitHub, SSH, cloud, Vault, Kubernetes and model provider keys, plus the AI tool and MCP tokens stored in the configuration files the payload read. Rotate from a machine that never installed the package.

After rotation, audit the accounts reachable from the host for unexpected repository creation, newly added workflow files and package publications, since those are the worm's propagation signals. Rebuild affected systems from trusted sources instead of cleaning them in place.

Two controls would have limited this incident, and neither is a package scanner. Socket flagged the release within minutes of publication and it was pulled the same day, so a minimum release age of even one or two days on new versions would likely have avoided exposure. Running installs with --ignore-scripts, or the npm v12 equivalent of leaving lifecycle scripts denied by default and allowlisting the packages that need them, closes the preinstall vector specifically. The CSA note adds that a later campaign moved its dropper out of the lifecycle script and into the package's main code, so script blocking should sit alongside runtime monitoring rather than replace it.

The habit worth changing is treating an agent-hosting SDK as an ordinary dependency. It runs on the same machine as the credentials your agents use, and the install hook does not wait for you to read it.

Primary sources

More from the wire