npm Supply Chain Attack: Protect Your Laravel Vite Build

· Development, Laravel

Table of contents

Between October 26 and 28, 2026, GitHub's advisory database published 112 malware advisories covering 106 packages, 96 of them on npm, according to a breakdown by Safeguard. In the same week, a self-spreading worm known as "testmetest" switched to a trigger that the usual --ignore-scripts advice no longer blocks. I write PHP for a living, but every Laravel and Magento project I maintain has a package.json for Vite, Tailwind or a Hyvä theme, and npm install runs on my laptop, in CI and sometimes on the deploy server. Here is what changed this month and the npm supply chain attack checklist I now apply to every PHP project.

What happened in October 2026

Two things stand out in the reports from the last days of October.

The volume. Safeguard counted 112 advisories in three days (65 on October 26, 27 on the 27th, 20 on the 28th), affecting 156 npm package versions. The payloads are the usual mix: postinstall scripts that install a crypto miner, beacons that send the hostname and install path to a remote server, a package that runs npm publish with the installer's own credentials, and infostealers that collect SSH keys, browser data and development credentials.

The worm. Ostorlab's analysis of the testmetest campaign describes malware that steals SSH keys, npm, PyPI and Git credentials, .env files and CI secrets, pushes the stolen data to new public repositories on the victim's GitHub account, then republishes itself with the stolen tokens. Worm releases were published to npm between October 19 and 21. On October 27, one package moved its dropper into a native addon's initialisation function, so the malware runs as soon as the package is loaded, with no install script at all.

That last point matters. "Just set ignore-scripts" was the standard advice after the big worms of 2025 and August's ChainDrop wave. It is still worth doing, but it is no longer enough on its own.

Why PHP projects are exposed too

It is easy to think of this as a JavaScript problem. It isn't. A typical Laravel app runs npm install && npm run build to compile its assets with Vite. A Magento store with a Hyvä or custom theme does the same for Tailwind. That build usually happens in places that hold very valuable secrets:

  • Your laptop, with SSH keys to every server you manage, your Git credentials and a few .env files with production API keys.
  • Your CI runner, with deploy keys, registry tokens and cloud credentials in its environment.
  • Your server, if your deploy script runs npm ci on production. Plenty of deploy scripts do this, and it means a malicious package runs next to the live .env.

The malware doesn't care that the application is written in PHP. It only needs Node to run a script or load a module.

Check your lockfiles now

First, find out whether anything you installed this month is on the lists. The reports name families such as testmetest, iobandamwer and testsecuiitytestme. From the root of each project:

grep -nE "testmetest|iobandamwer|testsecuiitytestme" package-lock.json
npm ls --all | grep -E "testmetest|iobandamwer|testsecuiitytestme"
npm audit

Do the same in your global packages (npm ls -g) and in any CLI tools you installed recently. If you get a hit on a full worm version, both analyses treat it as a host compromise. Ostorlab recommends disconnecting the machine, removing the persistence services before revoking the stolen GitHub token (revoking it first triggers a wiper), rotating every credential reachable from that machine, and rebuilding it. Rotate from a different, clean machine.

Harden npm installs in Laravel and Magento projects

These are the changes I made, roughly in order of value for effort.

  1. Always use npm ci in CI and deploys. It installs exactly what package-lock.json says and fails on drift, so a new malicious patch release can't slip in through a loose ^ range.
  2. Commit the lockfile and review its diff. A dependency bump that pulls in a package you have never heard of is the moment to stop and look.
  3. Turn off lifecycle scripts by default. Most Vite and Tailwind setups build fine without them. Add this to the project's .npmrc:
ignore-scripts=true

If one package genuinely needs its install script, run it explicitly for that one package (npm rebuild <package> --ignore-scripts=false) rather than enabling scripts for everything. Remember the limit: this blocks postinstall payloads, not code that runs on import.

  1. Pin private scopes to your own registry, so a public package with the same name and a higher version number can't win (the dependency-confusion trick in this month's batch used versions like 99.0.1):
@mycompany:registry=https://npm.internal.example.com/
  1. Build assets in CI, not on production. Ship the compiled public/build directory as an artifact and keep Node off the web server entirely. If the build environment is compromised, it at least doesn't sit next to the production database credentials.
  2. Give the build job as few secrets as possible. A Vite build doesn't need your deploy key or your Stripe secret. Split jobs so the one that runs npm ci has no access to them.

Don't forget the Composer side

PHP has the same risk in theory, and Composer has caught up on defences. Composer 2.10, released at the end of May 2026, added a dependency policy framework with malware blocking on by default: versions flagged in the Packagist.org malware feed are removed from resolution, and the check also applies to composer install from an existing lockfile. composer audit now fails when it finds malware.

Older Composer versions have no concept of these policies and will keep installing flagged versions. So the PHP half of the checklist is short:

composer self-update
composer --version   # 2.10 or later
composer audit

Check your CI images and Docker base images too: a pinned composer:2.8 image won't block anything. And don't disable the policies with "policy": false or COMPOSER_NO_BLOCKING just to make a red build green.

Conclusion

The October 2026 npm supply chain attacks are a reminder that a PHP project's attack surface includes its front-end toolchain. My checklist for every Laravel and Magento project: grep the lockfiles for the reported package families, switch CI and deploys to npm ci, set ignore-scripts=true, build assets in CI instead of on production, keep secrets away from the build job, and upgrade Composer to 2.10 so the PHP side blocks known malware too. None of this takes more than an hour per project, and it closes the door that the next worm will try first.