On the night of 22 May 2026, an attacker with a stolen GitHub personal access token rewrote the release tags of four Laravel-Lang packages, widely used community translation libraries for the Laravel PHP framework. Instead of publishing new versions, the attacker pointed existing tags at malicious commits in a fork, so anyone installing or updating any historical version through Composer received a credential stealer. The added file loaded automatically with Composer's autoloader, contacted a command server and fetched a PHP stealer that targeted cloud keys, CI secrets, SSH keys, browser passwords and crypto wallets. StepSecurity and Aikido raised the alarm on 22 May, and Packagist removed the malicious versions. The maintainers said the token belonged to one team member and "quite likely" leaked in GitHub's recent data breach. Estimates of affected versions range from 233 to about 700. The number of victims is not known.
Key takeaways
- Between 22:32 on 22 May and midnight UTC, every release tag in laravel-lang/lang, http-statuses, attributes and actions was moved to malicious code, according to StepSecurity and the maintainers.
- The maintainers traced the attack to a compromised GitHub personal access token of one team member, which they believe probably came from GitHub's recent data breach. StepSecurity described it as "one compromised credential with org wide push access".
- The payload,
src/helpers.php, ran whenever an application or CI job loaded Composer's autoloader, then fetched a stealer that Aikido says targets cloud, Kubernetes, Vault, Git and CI credentials, password managers and wallets. - Aikido counted 233 compromised versions and Socket estimated about 700. Packagist removed the malicious versions; no figures for downloads or victims have been published.
- The identity lesson: one personal access token with organisation-wide push rights was enough to poison every past release, so release tags need the same protection as the tokens that can move them.
At a glance
| Organisations | Laravel-Lang, a community project (not the official Laravel project); PHP developers and CI pipelines that installed or updated its packages through Composer and Packagist |
|---|---|
| When | First suspicious activity 21 May 2026; tags rewritten 22 to 23 May 2026; disclosed by StepSecurity and Aikido on 22 May 2026 |
| Attacker | Unknown; no public attribution |
| Entry point | A team member's GitHub personal access token, which the maintainers believe was "quite likely" obtained from GitHub's recent data breach |
| Identities abused | A GitHub personal access token with organisation-wide push access; then victims' cloud keys, CI tokens, SSH keys, Git and package manager credentials and other secrets |
| Impact | 233 to about 700 historical versions of four packages served a credential stealer; victim numbers unknown |
| Category | NHI. Incident class: confirmed NHI breach (stolen GitHub token used to plant a credential stealer in a package supply chain) |
What happened
Laravel-Lang maintains translation packages that many Laravel applications pull in through Composer, PHP's package manager. Composer installs a version by resolving a Git tag, so whoever controls the tags controls what users receive. According to the maintainers' incident report, published by Andrey Helldar on 23 May, the first suspicious activity came at 14:27 UTC on 21 May, when the attacker downloaded archives of two empty private repositories, probably as a test. The attack itself began at 22:32 UTC on 22 May and ended at midnight.
StepSecurity's Varun Sharma described the technique: "Rather than publishing a new malicious version, the attacker rewrote every existing git tag in each repository". In laravel-lang/lang alone that meant all 502 tags. Aikido explained why it was hard to see: "GitHub allows version tags to point to commits from a fork of the same repository", so "the malicious code was never committed to the official repos at all." Each poisoned tag added src/helpers.php to Composer's autoload list, so the code ran whenever an application, command or CI job required vendor/autoload.php. It fingerprinted the machine, decoded a hidden command server address, downloaded a second stage and deleted its traces.
Aikido found the second stage to be a roughly 5,900-line PHP stealer with 15 collector modules. It searched for AWS, GCP, Azure and other cloud platform credentials, Kubernetes and Vault tokens, SSH keys, Git credentials, package manager tokens, GitHub and GitLab CLI tokens, .env files, saved browser passwords, password manager vaults, crypto wallets and messaging bot tokens, then encrypted and sent the results to the attacker. BleepingComputer reported a Windows component that extracts browser encryption keys. In CI, StepSecurity said the stealer would most likely capture GITHUB_TOKEN and anything else in the job's environment.
Aikido reported the attack to the maintainers and Packagist on 22 May, and Packagist removed the malicious versions and temporarily unlisted the packages. The maintainers wrote that the incident came from a compromised personal access token belonging to one team member, "quite likely" from the recent GitHub data leak, though Snyk notes that link is presumed rather than confirmed. They removed write access for all team members, revoked tokens and SSH keys and disabled GitHub Actions for the organisation, after deleting the tags failed because they kept being restored. Their advice to others: revoke personal GitHub tokens and "Do not store secrets in repositories!!!"
Timeline
| Date | Event |
|---|---|
| 21 May 2026 | At 14:27 UTC the attacker downloads archives of two empty private repositories, the first suspicious activity in the audit logs. |
| 22 May 2026 | From 22:32 UTC the attacker rewrites the tags of laravel-lang/lang, then the other packages. |
| 22 May 2026 | StepSecurity publishes an alert; Aikido detects the attack and reports it to the maintainers and Packagist. |
| 23 May 2026 | Tag rewriting ends at 00:00 UTC with laravel-lang/actions; Packagist removes the malicious versions. |
| 23 May 2026 | The maintainers publish their incident report naming a compromised personal access token; BleepingComputer, Aikido and Snyk report on the attack. |
| 25 May 2026 | Snyk updates its advisory: the packages are relisted after remediation and version numbers alone cannot show whether a system was exposed. |
How it happened: the identity attack path
- A personal token leaks. A Laravel-Lang team member's GitHub personal access token was compromised, which the maintainers believe probably happened in GitHub's own breach.
- Reconnaissance with the token. The attacker tested access by downloading private repository archives about a day before the attack.
- Tags rewritten. With organisation-wide push access, the attacker deleted and recreated every release tag to point at malicious commits in a fork.
- Composer delivers the payload. Developers and CI jobs installing any version received
src/helpers.php, which ran automatically on autoload. - Victims' credentials stolen. The second stage harvested cloud, CI, SSH, Git and browser credentials and sent them to the attacker's server.
Impact
- Confirmed: four Laravel-Lang packages served malicious code through rewritten tags; Aikido counted 233 compromised versions and Socket estimated about 700.
- Confirmed credential abuse: a team member's GitHub personal access token was used to change the organisation's repositories, according to the maintainers.
- Unknown: no download or victim counts have been published. StepSecurity warned that "we may only have spotted the loudest cases", and Snyk says version numbers cannot show whether a system was affected.
- Potential: any credential on a machine or CI runner that installed or updated an affected package between 22 and 23 May 2026 should be treated as stolen.
What this means for NHI governance
This attack needed no flaw in Composer or GitHub. A single personal access token, with push rights across the whole organisation and no restriction on what it could change, let the attacker rewrite the entire release history. Because the token belonged to a person but acted like an automation credential, it sat in a grey zone that few teams govern well. If the maintainers are right that it leaked in GitHub's breach, it also shows how one platform's incident flows into many downstream projects through tokens nobody thought to rotate.
Tags are mutable references, so they are only as trustworthy as the identities that can move them. Fine-grained, expiring tokens, tag protection rules and pinning to commit hashes would each have limited this attack. See our Secrets Management Guide and CI/CD Pipeline Identity Security Guide.
Recommendations
- Revoke and replace broad personal tokens. Swap classic tokens for fine-grained, expiring tokens scoped to the repositories and actions each person needs, and rotate all tokens after any platform breach. See the Leaked Credential Response Playbook.
- Protect release tags. Use tag protection or repository rulesets so release tags cannot be deleted or moved without review.
- Pin dependencies to commit hashes. Lock files that record the exact commit, rather than a tag, stop a rewritten tag from changing what you install. See our CI/CD Pipeline Identity Security Guide.
- Rotate secrets on any machine that installed the packages. Include cloud keys, CI tokens, SSH keys, Git and package manager credentials and saved browser passwords.
- Keep secrets out of build environments. Give CI jobs short-lived credentials and keep long-lived keys out of
.envfiles and developer machines. See our Secrets Management Guide. - Watch audit logs for token reconnaissance. Alert on archive downloads, tag deletions and bulk tag changes, which preceded and marked this attack.
Frequently asked questions
What happened to the Laravel-Lang packages?
On 22 and 23 May 2026 an attacker used a stolen GitHub personal access token to move every release tag of four Laravel-Lang packages to malicious commits. Installing or updating any version through Composer ran a dropper that fetched a credential stealer. Packagist removed the malicious versions.
Was the official Laravel framework compromised?
No. Laravel-Lang is a third-party community project that provides translations for Laravel, not part of the official Laravel project. Only applications that installed or updated the affected Laravel-Lang packages during the attack were exposed.
Was the Laravel-Lang attack linked to the GitHub breach?
The maintainers said the compromised token "quite likely" came from GitHub's recent data breach and linked to GitHub's report on unauthorised access to its internal repositories. Snyk describes the link as presumed, and it has not been independently confirmed.
Related NHI Mgmt Group resources
GitHub Internal Repositories Breach 2026 · TrapDoor Supply Chain Campaign 2026 · Megalodon GitHub Actions Attack 2026 · Secrets Management Guide · Leaked Credential Response Playbook
How NHI Mgmt Group can help
Personal access tokens often behave like machine credentials but are governed like nobody's. We help teams find long-lived tokens, replace them with scoped, expiring credentials and build a rotation plan that kicks in when a platform they depend on is breached. See our NHI and AI agent security training.
References
- StepSecurity: Laravel-Lang Supply Chain Attack: Every Tag Across Multiple Composer Packages Rewritten to Steal CI Secrets (22 May 2026)
- Aikido Security: Supply Chain Attack Targets Laravel-Lang Packages with Credential Stealer (23 May 2026)
- BleepingComputer: Laravel Lang packages hijacked to deploy credential-stealing malware (23 May 2026)
- Snyk: Laravel Lang Supply Chain Advisory (23 May 2026)
- Habr (Laravel-Lang maintainers): Malicious attack on Laravel-Lang (23 May 2026)
- GitGuardian: Four Credential-Harvesting Campaigns Hit Open Source Ecosystems in Two Weeks (3 June 2026)