Poisoned Pipeline / Incidents / AS302
tensorlake 0.5.144 steals tokens, then wipes the home directory if they are revoked
npmGit / GitHubGitHub ActionsDeveloper workstationAI coding agentsVS Code / IDELinux distro / packagesWindows software
On 8 October 2026 StepSecurity reported tensorlake@0.5.144 on npm,
published 01:12 UTC, with a preinstall of node lib/setup.mjs. At that
collection the registry still listed 0.5.144 as latest. Version 0.5.143
was published 6 October and is the pin StepSecurity recommends. On
9 October the registry version endpoint for 0.5.144 returned 404.
latest was 0.5.145, published 20:24 UTC on 8 October.
The payload files were committed to main of tensorlakeai/tensorlake.
StepSecurity names the range e90c47b to 6386121 and says the first
commit landed at 01:20 UTC on 7 October, with seven more over the
following hours, none through a pull request. GitHub shows 13 commits
in that range, all authored as Shanshan Wang (login cooleel). The first,
"Add files via upload", was committed through the web UI (committer
web-flow). The last is 23:41 UTC the same day. Neither the blog nor
the commits establish that the named person was the operator.
At 00:08 UTC on 8 October, cooleel started a workflow_dispatch of
"Release - TypeScript SDK (npm)" on 6386121 (Actions run 37706134202).
It succeeded. npm recorded the 0.5.144 publish at 01:12 UTC, matching
StepSecurity. The package carries a provenance attestation because it
was built from that repo's main. The attestation names the build. It
does not say the commit was safe.
setup.mjs skips CI, so developer machines are the target. It downloads
the Bun runtime and runs an obfuscated 856 KB file, which StepSecurity
decoded without executing. The payload collects GitHub and npm tokens,
cloud keys, Kubernetes and Vault secrets, SSH keys, saved browser
logins, and config for Claude, Cursor, and Windsurf. It encrypts that
data and sends it to a public GitHub repo it creates in the victim's
account, or to iseekaigogo.com. The repo description the payload sets
is attacker branding. It is not, by itself, evidence of which wave
this build belongs to.
With a stolen npm token it downloads the victim's packages, adds
itself, bumps the version, and republishes them. With a stolen GitHub
token it commits .claude/settings.json (a SessionStart hook) and
.vscode/tasks.json (a folderOpen task) into repos it can write, as
claude@users.noreply.github.com, message "chore: update dependencies".
If it has a GitHub token it also installs gh-token-monitor. For up to
24 hours the service checks that token against the GitHub API every
60 seconds. If GitHub rejects it, the service runs rm -rf ~/ on Linux
or macOS, or a PowerShell delete of the user profile on Windows.
Revoking the token is what starts the wipe. StepSecurity told
maintainers in tensorlakeai/tensorlake issue 1014. No OSV or GHSA
record existed at that collection. MAL-2026-17650 was published at
02:54 UTC the same day and covers 0.5.144 only. No report names a
downstream victim.
SafeDep, Aikido, and Socket wrote up the same publish on 8 October.
Maintainers merged pull request 1016 at 04:32 UTC that day to revert
the commits on main. SafeDep reads the payload as a Mini Shai-Hulud
build: cipher salt svksjrhjkcejg, which it also reports for the keyv
wave, plus Ethereum contract
0xb614155Fd88114d40549b259457Bcf921Df091B9. Aikido records a
package-specific worm tag and says the PyPI and Cargo packages were
not published. That family read is not a reason to merge this publish
into the earlier keyv story. The package, the account, and the date
are this incident.
Mapped techniques
- T0111 Malicious code contribution to an open-source repository
- T0121 Compromised legitimate artifact
- T0166 Trigger pipeline execution
- T0109 Publish malicious artifact
- T0151 Installation scripts
- T0159 Malicious artifact execution
- T0184 Harvesting sensitive information from files
- T0210 Poison AI coding-agent config or workspace
- T0169 Push implants across repositories
- T0195 Spoofed Commits
- T0216 Wipe developer profile if a stolen token is revoked
supply-chain Poisoned main and the release workflow
Thirteen commits on main, e90c47b through 6386121, authored as
Shanshan Wang (cooleel). The first was a web-UI upload. No pull
request. Compromise of that person is not established.
tensorlake is the project's own npm package. 0.5.144 replaced
0.5.143 as latest. The files on npm match main.
workflow_dispatch of the TypeScript SDK npm release by cooleel,
Actions run 37706134202, started 00:08 UTC on 8 October on
commit 6386121 and succeeded.
tensorlake@0.5.144 published 01:12 UTC on 8 October and was
still npm latest at collection. preinstall runs node lib/setup.mjs.
post-supply-chain Install on a developer machine
The preinstall hook runs setup.mjs. It skips itself on CI.
setup.mjs downloads Bun and runs an obfuscated 856 KB file.
StepSecurity decoded that file without running it. Bun here is
a downloaded interpreter for the payload, not a compromised
compiler.
GitHub and npm tokens, cloud keys, Kubernetes and Vault secrets,
SSH keys, saved browser logins, and Claude, Cursor, and Windsurf
config. These are capabilities in the decoded file, not a named
victim theft.
Stolen GitHub tokens are used to commit a SessionStart hook in
.claude/settings.json and a folderOpen task in .vscode/tasks.json.
The same GitHub token commits those files into repos the token
can write. A stolen npm token is used to republish the victim's
own packages with the payload added.
Spread commits use author claude@users.noreply.github.com and
the message "chore: update dependencies".
gh-token-monitor polls the stolen GitHub token every 60 seconds
for up to 24 hours. If GitHub rejects it, the service deletes
the home directory (Linux, macOS) or the user profile (Windows).
Framework gaps noted
- The commits and the workflow_dispatch use login cooleel. The write-up does not establish compromise versus an authorized maintainer, so this is not mapped as T0113.
- npm provenance on 0.5.144 is a real attestation of the poisoned main build. That is not T0206, which is forging or omitting provenance.
- Exfiltration to a public repo created in the victim account, or to iseekaigogo.com, is not T0156 (webhooks).
- The CI skip and the Bun download have no separate technique.
- The description the payload writes on its exfil repo is branding. SafeDep's salt match is a family link to the keyv wave, not the same operation.
- No confirmed downstream install is in the reports. MAL-2026-17650 covers 0.5.144. No GHSA id.
Sources
- https://www.stepsecurity.io/blog/tensorlake-npm-compromised-hostage-token-worm
- https://github.com/tensorlakeai/tensorlake/issues/1014
- https://github.com/tensorlakeai/tensorlake/commit/e90c47bbb208e99cac8aa678405b2133f6cb3f52
- https://github.com/tensorlakeai/tensorlake/commit/6386121c561e74fec143a138d5cc3d3bbabdfe8c
- https://github.com/tensorlakeai/tensorlake/actions/runs/37706134202
- https://www.npmjs.com/package/tensorlake
- https://osv.dev/vulnerability/MAL-2026-17650
- https://github.com/tensorlakeai/tensorlake/pull/1016
- https://safedep.io/tensorlake-npm-compromise-mini-shai-hulud
- https://www.aikido.dev/blog/tensorlake-npm-package-compromised
- https://socket.dev/blog/tensorlake-compromise
- https://checkmarx.com/zero-post/mini-shai-hulud-in-tensorlake-a-token-monitor-that-can-wipe-your-home-directory/