Someone with rights to move Git tags on the Laravel-Lang GitHub organization rewrote a large set of existing release tags so they pointed at new commits that only touched composer.json and src/helpers.php. Packagist still mapped those tags to laravel-lang/lang, laravel-lang/http-statuses, laravel-lang/attributes, and laravel-lang/actions, so Composer kept serving the same version labels with different bytes behind them. The maintainers’ post-incident write-up pins the root cause on a compromised personal access token that could rewrite tags, with activity from May 22 at 22:32 UTC through May 23 at 00:00 UTC (Habr investigation summary).
The injected composer.json adds src/helpers.php under autoload.files. In Composer that list is eager: each file is require-d as soon as vendor/autoload.php loads, before your app touches a class. Laravel, Symfony, PHPUnit, and most PHP stacks hit that autoloader on boot, so the dropper runs in CI, queue workers, and local dev, not only in web requests (Composer autoload schema). The Habr post reproduces the dropper: it builds the flipboxstudio.info hostname from integer character codes, fetches /payload, writes a short-lived PHP loader under the temp directory, and backgrounds php on Unix or cscript on Windows.
StepSecurity detonated laravel-lang/http-statuses v3.4.5 inside an isolated GitHub Actions runner. Their trace shows php -r "require 'vendor/autoload.php'; …" issuing GET https://flipboxstudio.info/payload, then a detached php child (ppid=1) issuing POST …/exfil, with rm removing the staged files within a few seconds (StepSecurity blog). On GitHub, poison commits carry the banner that the commit does not belong to any branch, which is what you expect when an attacker only force-moves tags and never merges to main.
Response matched the urgency of the delivery channel. Maintainers report that Packagist unpublished laravel-lang/lang first, then they revoked write access for all members because tag deletion alone failed; tags were being restored while the stolen credential still worked. After that came PAT and SSH key rotation and GitHub Actions disabled at the org (Habr). The pattern rhymes with Packagist’s May 2023 incident, where dormant maintainer accounts were used to fork packages and repoint tags, only here the pivot is org-level GitHub credentials plus Composer’s tag-to-dist path (Packagist maintainer-account takeover post).
If you are cleaning up instead of rubbernecking: treat any machine or runner that composer install / composer update pulled these packages on after 2026-05-22T22:32:00Z UTC as potentially compromised, not merely “out of date.” Inspect composer.lock entries for the four packages. If the source reference lands on or after that instant, or matches bad SHAs called out in the StepSecurity article for your pinned tag, rotate every secret that process could read (GitHub tokens, cloud keys, database URLs, signing keys) and hunt egress to flipboxstudio.info in DNS or proxy logs, because local filesystem indicators may already be gone. Until you trust restored tags again, composer install against a known-good lockfile beats composer update in CI for these dependencies.
GitHub has published its own investigation into unauthorized access to internal repositories; the Laravel-Lang team cites that broader leak context when explaining why a PAT might have shown up in the wrong hands (GitHub security blog). Whether or not you buy that exact chain for this org, the cheap win is the same: delete PATs you are not actively using, tighten org-wide scopes, and prefer fine-grained tokens or OIDC where GitHub documents them for your workload.
Sources
- Malicious attack on Laravel-Lang (maintainer post-mortem, Habr)
- Laravel-Lang supply chain attack: rewritten tags and CI detonation (StepSecurity)
- Composer
composer.jsonschema: autoload - Packagist.org maintainer account takeover (May 2023 precedent)
- Investigating unauthorized access to GitHub’s internal repositories (GitHub)