CybersecurityGrid Pulsar team··9 min read

npm Worm Still Spreading: Check Your Servers and CI

Check servers and CI for the ChainDrop npm worm, remove token-monitor persistence before revoking secrets, and rebuild with npm install scripts restricted.

npm Worm Still Spreading: Check Your Servers and CI featured image
On this page
Short answer

An npm dependency can infect a machine during installation, before your application imports it. Check developer machines, build runners and servers where dependency scripts ran. If you find ChainDrop or tensorlake indicators, isolate the host and remove token-monitor persistence before revoking credentials, following Socket's warning about destructive retaliation. Rotate exposed secrets from a clean machine, rebuild affected systems, and adopt npm v12 with narrowly reviewed script permissions.

Treat dependency installation as the exposure point

You might assume an npm package cannot compromise your server unless your application imports it. That belief fails when installation runs a malicious lifecycle script with the installing user's access. Check every machine that installed dependencies, including CI runners, before deciding your production server is clear.

In its analysis published on 4 August 2026, Microsoft describes ChainDrop, also called Mini Shai-Hulud, affecting more than 400 npm packages across unrelated publishers, including keyv, flat-cache and cache-manager. Its malicious setup.mjs runs through preinstall and launches an obfuscated Bun-based payload. Microsoft reports that the payload detaches on workstations but remains attached in CI/CD to access job secrets.

Socket's tensorlake investigation reports that tensorlake 0.5.144 was published on 8 October 2026 at 01:12:07 UTC and flagged about 11 minutes later. Its preinstall hook runs node lib/setup.mjs, which launches the payload with Bun; importing the SDK is unnecessary. That later compromise is a reason to examine recent installations, even if you already reviewed the earlier incident.

For an Ubuntu 24.04 LTS VPS, start by establishing where builds happen and which account runs them. We would pause dependency installation while investigating, including agent-initiated installs. A running application can remain available while you suspend deployment jobs, provided there is no evidence requiring immediate host isolation.

Decide which machines and credentials need investigation

What you findWhat you do
An affected package was installed with lifecycle scripts enabledTreat the installing machine and its accessible credentials as potentially compromised.
A package appears in a lockfile, but execution history is unclearPause installs and examine runner logs, installed files and script policy.
A server only receives built artifactsInvestigate the build environment and artifact provenance; check whether dependency installation also happens during deployment.
Token-monitor persistence or suspicious repository setup filesIsolate the machine and follow the persistence-first recovery order.

Microsoft says the worm seeks npm, GitHub, AWS, Kubernetes and HashiCorp Vault credentials, alongside environment variables, SSH keys and GitHub Actions runner memory. It validates stolen credentials against service APIs. Build your rotation inventory around what the installing account could access, rather than what the application normally uses.

A short-lived runner does not make its credentials harmless. Review the permissions and lifetime of credentials available during installation, then identify downstream systems those credentials could reach. Our guide to scoped secrets for agents helps reduce that exposure when you rebuild.

Keep a private incident record containing machine identities, installation evidence and affected credential names. Do not paste token values, environment dumps or complete process environments into an agent conversation. Give Claude Code bounded inspection tasks using the approach in production agent guardrails, and retain control of credential replacement.

Inspect installed files without running package code

Begin with filesystem inspection, without launching the application or asking npm to repair dependencies. The following command searches common account and service locations for loader names and the token-monitor directory. Repeat it against your actual checkout and runner-storage locations if they live elsewhere.

bashTested on Ubuntu 24.04
sudo find /home /root /srv /opt -xdev \( -type d -name gh-token-monitor -print \) -o \( -type f \( -name setup.mjs -o -name package-lock.json -o -name npm-shrinkwrap.json -o -name yarn.lock \) -print \)
Check: The output identifies files and directories to investigate. A setup.mjs filename alone is not proof of malware, and no matches do not establish that a host is clean.

In each affected checkout, inspect the dependency tree and lockfiles without installing anything. These commands assume you are already in the real project directory with its existing Node.js tooling; they are project investigation commands, not fresh-server setup. Keep any results containing private registry addresses inside your incident record.

bash
npm ls tensorlake keyv flat-cache file-entry-cache cacheable cache-manager --all --ignore-scripts
 git grep -n -E 'tensorlake|keyv|flat-cache|file-entry-cache|cacheable|cache-manager' -- package-lock.json npm-shrinkwrap.json yarn.lock
Check: Dependency paths and lockfile entries identify direct and transitive packages for comparison with the official advisories. npm ls can exit unsuccessfully for an incomplete tree; a missing dependency tree does not prove an earlier install never happened.

Read suspicious package manifests and loader files as text. Compare resolved releases with the advisories, and preserve installation logs before replacing runners or clearing caches. A matching tensorlake 0.5.144 entry establishes dependency exposure, while logs showing its hook ran establish a stronger reason to treat the machine as compromised.

Check repository hooks and runner persistence

Microsoft reports repository injection involving .claude/settings.json, .claude/setup.mjs, .vscode/tasks.json and .vscode/setup.mjs. Inspect these files before opening a suspect checkout in an editor or starting Claude Code there. Legitimate configuration can use these paths, so investigate their contents and history rather than deleting every matching file.

bash
git status --short --untracked-files=all
 git log --all --format=fuller -- .claude/settings.json .claude/setup.mjs .vscode/tasks.json .vscode/setup.mjs
 git diff -- .claude/settings.json .claude/setup.mjs .vscode/tasks.json .vscode/setup.mjs
Check: Review unexpected commits and local changes for commands that launch setup files. A clean working-tree diff does not clear files already committed to a branch.

Inspect other branches through your repository interface from a clean machine, without checking them out on the suspect host. Include automation branches and changes made by identities whose tokens were exposed. Protect the repaired deployment path using bounded GitHub Actions access to a VPS.

Socket identifies a Linux gh-token-monitor service with files under ~/.config/gh-token-monitor/. Run these checks under each account that installed dependencies, then inspect the system service separately. User-service inspection requires that account's functioning systemd session.

bash
systemctl --user list-unit-files 'gh-token-monitor*' --no-pager
systemctl --user status gh-token-monitor.service --no-pager
sudo systemctl list-unit-files 'gh-token-monitor*' --no-pager
sudo systemctl status gh-token-monitor.service --no-pager
ps -eo user,pid,ppid,comm
Check: A matching service or configuration directory requires investigation. An absent unit is only a negative result for that account and service scope; inspect suspicious processes and deployment history as well.

Isolate the host before removing persistence and rotating secrets

Socket warns that the tensorlake token monitor polls api.github.com/user using the stolen token and can invoke a handler that wipes the user's home directory after revocation. Its remediation order is explicit: identify and isolate affected hosts, remove the monitor, then revoke and replace credentials before rebuilding. Do not begin recovery by revoking a token while a suspect host remains active and connected.

Use your provider's network controls or console to isolate the VPS, and take affected runners out of service. Preserve relevant evidence without executing suspect files. If you cannot confidently neutralize persistence on a live machine, keep it powered off and disconnected while arranging recovery.

For a confirmed user-scoped unit, stop and disable it under the affected account. The commands below change service state, so run them only after isolation and inspection. A system-scoped service requires the corresponding system-level action, and removing a unit does not by itself remove a running child process.

bash
systemctl --user disable --now gh-token-monitor.service
systemctl --user is-active gh-token-monitor.service
systemctl --user is-enabled gh-token-monitor.service
Check: Expect inactive and disabled states, with nonzero exit statuses from the inspection commands. Confirm the monitor process has stopped, then quarantine its inspected executable, configuration and unit files before treating persistence as removed.

Rotate credentials from a clean machine after persistence is neutralized or the affected machine is safely offline. Replace exposed SSH keys and inspect account activity for unauthorized changes. Rebuild a confirmed compromised VPS from trusted installation media; do not return the old filesystem to service after merely deleting a loader.

Patch npm on clean build machines and review script permissions

GitHub announced npm v12 availability on 8 July 2026. Its allowScripts default is off, so dependency preinstall, install, postinstall and implicit node-gyp builds require explicit permission. Updating a clean build environment reduces future installation exposure; it does not undo code execution on a compromised machine.

Use your established Node.js installation method and check npm's runtime requirements before updating. On a clean machine with a compatible runtime and a user-owned npm installation, the following installs npm v12 without package installation scripts. For a centrally managed toolchain, make the equivalent change in its image definition instead of mixing ownership with an ad hoc sudo installation.

bash
npm install --global npm@12 --ignore-scripts
npm --version
Check: The reported npm major version must be 12. Check it inside the actual CI job too, because updating your interactive shell does not update a runner image.

GitHub also says npm v12 defaults --allow-git and --allow-remote to none; these behaviors showed warnings in npm 11.16.0 and later. Review blocked scripts in a clean checkout with the command below, as GitHub recommends. Commit the resulting allowlist in package.json only after reviewing each permission.

bash
npm approve-scripts --allow-scripts-pending
Check: Inspect the pending script list and resulting package.json changes. Approval is justified by inspected package behavior and build need, not by the fact that a dependency previously installed successfully.

Keep permissions narrow when native dependencies need build steps. Do not restore broad script execution simply to make a failing pipeline green. Review repository npm configuration and CI command-line overrides alongside the allowlist, since your effective installation policy depends on the configuration actually used.

Rebuild dependencies without restoring contaminated caches

Microsoft recommends reviewing lockfiles and CI caches, including transitive dependencies, purging npm and yarn caches, and using npm's min-release-age setting. Apply an intentional release-age policy using the official npm guidance for your installed CLI. An age delay creates review time, but it cannot establish that a dependency is trustworthy.

Preserve evidence before clearing caches, then invalidate runner caches and rebuild from a reviewed lockfile. The npm command below removes the invoking account's npm cache; it does not clean another account's cache or your CI provider's stored archives. For yarn, identify the installed tooling and follow its cache-cleaning procedure rather than guessing a command.

bash
npm cache clean --force
npm ci --ignore-scripts
Check: The clean install must use the reviewed lockfile and complete without lifecycle scripts. If the build requires approved dependency scripts, enable only those reviewed permissions in a separate controlled build.

Do not rely on blocking the earlier incident's domains as your recovery criterion. Socket says the tensorlake payload resolves its command infrastructure through an Ethereum contract, with a GitHub fallback. Network controls help contain a host, but a domain blocklist cannot substitute for eliminating execution and replacing exposed credentials.

Gate the next deployment on clean build evidence

Before reopening deployment, record which clean machine produced the artifact and which reviewed commit it used. Confirm the runner reports npm v12 and that its script permissions match the committed policy. Keep build credentials separate from the production account wherever your deployment design permits.

  • Confirm exposed credentials were replaced from a clean machine after affected hosts were neutralized.
  • Check repository branches and automation configuration for unexpected setup execution.
  • Rebuild without restoring suspect dependency caches, then run your application's normal validation.
  • Deploy to the rebuilt VPS and confirm the service works with its intended permissions.

If you publish npm packages, review every package controlled by an exposed publishing identity. Microsoft describes propagation through republishing modified packages under stolen publisher access. GitHub recommends trusted publishing through OIDC or staged publishing with human approval as part of its publishing-token changes.

Make your next action a paused deployment and an inventory of machines that installed the affected dependency tree. Assign investigation by machine and credential owner so a developer laptop does not fall outside a server-focused response. Once the clean deployment works, apply the relevant checks from the Ubuntu hardening checklist before restoring routine agent access.

FAQ

How do I check whether my server was affected by the npm supply chain attack?

Inspect the dependency tree, lockfiles and installation logs under the account that performs deployments. Compare resolved packages with the official advisories, then inspect suspicious setup files and services without running them. Include CI runners and developer machines. A filesystem search can identify evidence, but missing files cannot establish that malicious code never executed.

What is the safe remediation order for Shai-Hulud or ChainDrop?

Start by containing affected machines and preventing further installation jobs. Socket warns that the tensorlake token monitor can react destructively to token revocation, so neutralize persistence or keep affected hosts offline before replacing credentials. Perform account recovery from a clean machine, inspect repository changes, and rebuild compromised systems using reviewed dependencies and clean caches.

Does the tensorlake npm compromise require importing the SDK?

No. Socket reports that tensorlake 0.5.144 executes its loader through a preinstall hook, so the installation itself is the relevant event. Review whether lifecycle scripts were permitted when the dependency was installed. Removing an unused import or uninstalling the SDK afterward does not address credentials or persistence exposed during installation.

Are npm v12 install scripts disabled by default?

GitHub says npm v12 blocks dependency lifecycle scripts and implicit native builds unless explicitly allowed. That changes the default installation behavior, but you still need to inspect project permissions and CI overrides. Review pending scripts with npm's approval workflow, commit justified permissions, and check the CLI inside each runner rather than assuming it matches your laptop.

Can I fix an infected VPS by updating npm and clearing its cache?

Those changes help prepare a clean environment, but they cannot reverse actions already taken by malicious code. Treat secrets available to the installing account as potentially exposed and investigate unauthorized account or repository changes. For confirmed execution, rebuild the VPS after containment and credential recovery instead of trusting an installation cleanup as complete remediation.

Free ebook

Put this guide in the bigger picture

See how this topic connects to the rest of your product. Our free field guide explains apps, infrastructure and AI, with checklists to help you make business decisions.

We use cookies to ensure that we give you the best experience on our website. If you continue to use this site we will assume that you are happy with it.