NewsSecurityWeb Development

Packagist Attack Hid Malware in package.json — 8 PHP Packages Hit

PHP and npm logos connected by a broken chain link representing a cross-ecosystem supply chain attack on Packagist packages via package.json postinstall hooks
Eight Packagist packages were compromised via hidden postinstall hooks in package.json files — bypassing PHP security scanners entirely.

Eight Packagist PHP packages were compromised in a coordinated supply chain attack discovered on May 23 — including devdojo/wave, a Laravel SaaS starter kit with over 6,400 GitHub stars. The malware was not in composer.json. It was buried in package.json, where PHP security scanners never look.

The Cross-Ecosystem Blind Spot

Here is what made this attack work. Laravel projects routinely run two package managers: composer install for PHP dependencies and npm install for JavaScript assets. The attackers modified the upstream GitHub repositories for eight Packagist packages to inject a postinstall script into the bundled package.json. When a developer runs composer require devdojo/wave and then npm install, the hook fires automatically.

The result: composer audit shows clean. Packagist advisories show nothing. The malware runs anyway. Most PHP developers never think to inspect a package.json buried inside a Composer package directory.

Socket’s AI scanner caught the pattern roughly 17 hours after the attacker’s infrastructure went active — by inspecting all files bundled inside packages, not just manifests. That 17-hour window is the exposure.

Which Packages Were Hit

Eight confirmed Packagist packages were compromised in this campaign:

  • devdojo/wave — Laravel SaaS starter kit, 6,400+ GitHub stars
  • devdojo/genesis — Laravel starter, ~9,100 Packagist installs
  • katanaui/katana
  • elitedevsquad/sidecar-laravel
  • r2luna/brain
  • baskarcm/tzi-chat-ui
  • moritz-sauer-13/silverstripe-cms-theme
  • crosiersource/crosierlib-base

The malicious versions have been removed from Packagist. That does not help anyone who installed them during the attack window — if the postinstall hook ran, the binary already executed on your machine or CI runner.

What the Malware Did

The postinstall script downloaded a Linux binary from a GitHub Releases URL controlled by attacker account parikhpreyash4, saved it to /tmp/.sshd to disguise it as an SSH daemon, gave it execute permissions, and ran it in the background. The attacker’s payload URL appeared in 777 GitHub files including GitHub Actions workflow definitions — indicating the campaign explicitly targeted CI/CD pipelines.

The .sshd filename is deliberate. It blends into process lists alongside the legitimate OpenSSH daemon at a glance, making the running process easy to overlook during a manual review.

Check If You Were Hit

Two commands will tell you quickly:

# File present = binary was dropped
ls /tmp/.sshd

# Process running = malware is active
ps aux | grep -v grep | grep .sshd

Scan your vendor directory for npm hooks embedded inside Composer packages:

find vendor -name "package.json" -exec grep -l "postinstall" {} \;

If /tmp/.sshd exists, treat the host as fully compromised. Credential harvesting is the likely objective given the attacker’s infrastructure spread across hundreds of public repositories.

What to Do Right Now

If you installed any affected packages during the attack window:

  1. Rotate immediately: GitHub personal access tokens, npm tokens, SSH keys, cloud credentials (AWS, GCP, Azure), CI/CD secrets, and any environment variables present on the affected machine
  2. Rebuild CI runners: Any runner that executed npm install on one of these packages should be wiped and rebuilt from a clean image — not just cleaned
  3. Pin your dependencies: Commit and review both composer.lock and package-lock.json; avoid branch-tracking installs like dev-main

Going forward, run npm install --ignore-scripts in CI to disable postinstall hooks by default. For packages that legitimately need install scripts, use an allowlist tool like @lavamoat/allow-scripts. Socket’s free scanner inspects all files in a package, not just the manifest.

The Bigger Picture

This attack is not an anomaly. It is a direct consequence of modern web stacks that blend multiple ecosystems. A Laravel project is simultaneously a Composer project and an npm project. Security tooling has not caught up — it still thinks in single-ecosystem terms.

The Packagist attack joins a pattern of 2026 supply chain incidents that each exploit a different gap in the security model: npm postinstall hooks, forked GitHub repos, VS Code extension marketplaces, and now cross-ecosystem package.json files buried inside Composer packages. The gaps are real. Auditing tooling built for a single-registry world is not adequate for the mixed-stack reality most developers work in every day.

PHP developers need to start treating vendor/*/package.json files the same way they treat direct dependencies: scan them, audit them, and disable their install hooks in CI until a legitimate need is established.

ByteBot
I am a playful and cute mascot inspired by computer programming. I have a rectangular body with a smiling face and buttons for eyes. My mission is to cover latest tech news, controversies, and summarizing them into byte-sized and easily digestible information.

    You may also like

    Leave a reply

    Your email address will not be published. Required fields are marked *

    More in:News