The Composer ecosystem just took a body blow. Between roughly 11:00 and 11:15 UTC on 22 May 2026, an attacker with push access to the Laravel-Lang GitHub organization rewrote tag references across four widely-used Composer packages, repointing 233 historical version tags to commits in a malicious fork. By the time the first detection signal hit researchers at Aikido and Socket later that afternoon, more than 700 historical versions across the dependency graph had been poisoned and an unknown number of CI pipelines had executed the payload.
The payload is a 5,900-line PHP credential stealer registered as an autoload file in composer.json, which means it runs on every PHP request handled by the compromised application, not just at install time. It targets cloud keys, SSH credentials, browser passwords, and CI secrets. Packagist has since delisted the affected versions, but the window of exposure was wide. If your team installed laravel-lang/lang, laravel-lang/http-statuses, laravel-lang/attributes, or laravel-lang/actions at any point in the last 72 hours — or your CI pulled them in a routine composer update — you are an incident.
Below is what happened, why the attack is a category, and the seven-step response playbook for this week.
1. The Mechanics: Tag Rewrite Is The Vector
Most supply-chain attacks on Composer or npm work by publishing a new, malicious version. Defenders catch them by watching for new versions of packages they did not expect. The Laravel-Lang attack did the opposite: it rewrote the references for versions that already existed. A composer install against ^1.0 on a package the team had been using for two years suddenly fetched a fork-controlled payload instead of the canonical commit.
The technical exploit is GitHub's permissive policy on fork references. A tag in a repository can point to a commit that lives in a fork of the repo, as long as the fork is reachable. The attacker, with push access to the Laravel-Lang organization, repointed tags across the four packages to commits in a fork they controlled, in which src/helpers.php had been replaced with the credential stealer. Composer's package resolution does not distinguish between commits in the source repo and commits in any reachable fork; the tag is the source of truth, and the tag now pointed to evil.
This pattern — tag rewrite via fork referencing — is the category that defenders should learn this week. It defeats both lockfile pinning (because the lockfile pins the tag, and the tag has been mutated) and version-range scrutiny (because no new version appears). The only defenses that work are commit hash pinning, install-time signature verification, or staged validation in a non-production environment.
2. What The Payload Actually Does
The credential stealer is one of the most thorough public-facing PHP malware artifacts of the last several years. Fifteen specialist collector modules, run from a single autoload.files entry, execute on every request the application serves. The modules target, in roughly the order they execute: cloud access keys (AWS, GCP application default credentials, Azure tokens, DigitalOcean tokens); infrastructure config (Kubernetes kubeconfig, Docker registry tokens, HashiCorp Vault tokens); developer secrets (SSH private keys, .git-credentials, .env files); CI/CD secrets (Jenkins, GitLab Runner, GitHub Actions); browser data (logins from 17 Chromium-based browsers, cookies, autofill, internal admin panel history); password managers (KeePass, 1Password local vaults); and crypto assets (desktop wallets, MetaMask, Slack tokens, Discord session files).
Everything is exfiltrated to an attacker-controlled endpoint. The notable design choice is that the stealer runs on every request, not at install time. A server that pulled the package on Friday afternoon, never restarted, and continued serving traffic over the weekend, has been leaking credentials every time it served a page.
3. The Seven-Step Response For This Week
If your team has any exposure, run this in order. Stop reading and run step one now if you are unsure.
Step one: identify exposure. composer show laravel-lang/* --installed on every server, CI cache, dev machine, and built container. If anything is returned with a version older than the May 23 delisting, you must assume compromise of whatever credentials that machine had access to.
Step two: rotate cloud keys. AWS access keys, GCP service-account keys, Azure SPN secrets, DO API tokens. Do this even if you "only" have the package on a dev laptop — the stealer runs on whatever box served the request.
Step three: rotate CI tokens. GitHub Actions tokens, GitLab Runner registration tokens, Jenkins API tokens, any deployment SSH key in your CI vault.
Step four: rotate SSH keys. Both the user-account keys on dev machines and the deployment keys in your CI vault. Force a re-registration on all key-based access.
Step five: rotate database and third-party API credentials. Anything in any .env file the application could read. This is the broadest category and the most painful, but it is the right answer.
Step six: audit Composer lockfiles in every repo. Any lockfile that pins to one of the affected versions needs to be regenerated against a known-clean source. Where possible, switch from tag pinning to commit-hash pinning for high-trust packages, at least temporarily.
Step seven: introduce dependency-installation scanning to CI. Tools like Socket, Snyk, Aikido, and Phylum now offer install-time scanning that can detect tag rewrites of this exact shape. Set the scanner to fail the build, not warn, on any tag drift.
The complete cycle, for a small Laravel shop with five-to-ten production servers and CI, is roughly a one-day project. For an agency with several dozen client codebases, plan two days minimum and assume one client will turn into a full forensic engagement.
4. The Larger Pattern And The Defensive Posture To Adopt
The Laravel-Lang attack is the third major Composer/npm supply chain compromise this calendar year that exploited "trusted maintainer push access" rather than a novel CVE. The defensive posture that has worked elsewhere — patch promptly, watch CVE feeds, rotate when prompted — is insufficient against this category. Two postures actually help.
Defense in depth at the install step. Treat composer install and npm install as untrusted code execution. Run them in containers with no access to credentials, never on a developer laptop with cloud keys present, never on a CI runner that has production deploy keys. The blast radius of any future tag-rewrite attack collapses to the install sandbox.
Provenance verification. Sigstore-style signed releases are now production-ready for both Composer and npm. The provenance check costs a few seconds at install time and would have caught the Laravel-Lang tag rewrite because the malicious commits were not signed by a maintainer. This is the most important hygiene investment of the next quarter; do not let "we are too busy" be the reason it does not happen.
The community-maintained, low-staffing package is the soft underbelly of the modern web stack. Laravel-Lang has between two and three active maintainers handling a package depended on by hundreds of thousands of repositories. The asymmetry between maintainer hours available and exploitation reward is structural; it will continue to produce these incidents. The right response is at the dependency-consumer side, not in expecting maintainer organizations to suddenly add a security team.
5. The Honest Read
For practitioners who have spent the last three years adopting more and more open source into the application bundle, the Laravel-Lang attack should provoke a reassessment. Pinning is not enough. Audit-trail-after-install is not enough. The only sufficient practices are sandboxing the install and verifying provenance at install time. Both have been technically possible for two years; almost no team does both.
The cost-benefit math just shifted. The cost of doing both is a couple of CI minutes and a day of pipeline work. The cost of not doing both is the slow accumulation of "did our credentials leak last week?" until one Tuesday morning the answer is yes.
My Take
The narrative I want to push back on is that this is "another supply chain attack" lumped in with the parade of similar incidents over the last 18 months. It is structurally different. Tag rewrite is the first attack technique that defeats lockfile pinning, the defense most teams adopted because of earlier supply chain attacks. The arms race has moved past the defenses most agencies last upgraded for. The pause-and-update moment is now, not after the next incident.
The other narrative I want to push back on is "we will wait for the official Laravel security advisory before acting." There is no central authority on community-maintained Composer packages. The Laravel core team is not responsible for Laravel-Lang; Packagist's role is distribution, not security; the Laravel-Lang maintainers are doing what they can but have a small team facing an incident of this scale. The responsibility for response sits with the application owner, and the response window closes faster than the official channels move. If you are on the Laravel stack and you have anything to lose, run the seven steps today.
Sources
- Laravel-Lang PHP Packages Compromised to Deliver Cross-Platform Credential Stealer — The Hacker News
- Supply Chain Attack Targets Laravel-Lang Packages with Credential Stealer — Aikido
- Laravel-Lang Compromised with RCE Backdoor Across 700+ Versions — Socket
- Supply Chain Storm: Over 700 Laravel Lang Versions Poisoned with Malicious RCE Backdoor — Security Online
- Hackers Compromised 233 Versions of Laravel-Lang Packages by Hacking 700 GitHub Repos — Cyber Security News