Skip to content

Laravel-Lang Composer packages hijacked — 700+ versions ship a credential stealer

Attackers rewrote Git tags across four Laravel-Lang repos to point at a malicious fork, planting a Composer-autoloaded stealer that runs on every request. Packagist has unlisted the packages.

Published 4 min read

A supply-chain attack on the Laravel-Lang localisation packages republished more than 700 historical versions on May 22 and May 23, each pointing at an attacker-controlled fork that drops a credential stealer. Every Composer install or update during the window pulled the malicious code, and because the payload is hooked into autoload.files, it executes on every request the consuming app handles.

Aikido Security and Socket discovered the campaign independently and disclosed within hours of each other. Packagist took the affected versions offline and temporarily unlisted the packages.

What's affected

The compromised packages, all maintained under the laravel-lang GitHub organisation:

  • laravel-lang/lang
  • laravel-lang/attributes
  • laravel-lang/http-statuses
  • laravel-lang/actions

These are third-party localisation libraries, not part of the official Laravel framework. laravel-lang/lang alone carries roughly 7.8k GitHub stars and is a default dependency in countless Laravel starter kits and admin templates.

Socket counts roughly 700 historical versions rewritten across the four repos. Aikido confirms 233 versions as carrying the malicious payload across three of them. The mismatch is the point: the attacker mass-republished tags so that any version a downstream composer.json might pin to would resolve to a poisoned commit.

How the attack worked

Packagist resolves a Git tag by fetching the commit it currently points to, not the commit it pointed to at release time. The attacker exploited that by force-pushing tags on the upstream repositories so they pointed at a fork they controlled. Composer's tag resolver dutifully fetched the new commit.

Inside each compromised version, the attacker added a src/helpers.php file and registered it under the autoload.files map in composer.json. Every Laravel app — and every framework that follows the same boot pattern, including Symfony and PHPUnit — calls require __DIR__.'/vendor/autoload.php' at startup. The stealer runs the moment that line executes. No class instantiation, no method call, no special trigger.

What the payload does

Socket's analysis describes a broad-spectrum credential scraper. It reaches for:

  • Cloud provider keys (AWS, GCP, Azure metadata endpoints and local credential files).
  • Kubernetes service-account tokens and kubeconfig files.
  • HashiCorp Vault tokens.
  • CI/CD secrets exposed through environment variables.
  • SSH private keys and known-hosts material.
  • .env files and other local configuration.
  • Browser-stored passwords and session cookies.
  • Password-manager vaults.
  • Cryptocurrency wallets.
  • Messaging app tokens.

The stealer ships harvested data to attacker-controlled infrastructure. Any developer workstation, CI runner, or production box that ran composer install or composer update against the affected window should be treated as having leaked everything reachable from the running process.

Action checklist

  1. Inventory. Grep your composer.json and composer.lock files across every repo for laravel-lang/lang, laravel-lang/attributes, laravel-lang/http-statuses, and laravel-lang/actions.
  2. Rotate credentials. Any host or CI runner that installed or updated those packages between May 22 and May 23 should have every secret reachable from the runtime rotated — cloud keys, Vault tokens, K8s service accounts, SSH keys, API tokens, the lot.
  3. Wipe and reinstall. Delete vendor/ and the offending entries from composer.lock, then reinstall once Packagist confirms the affected packages have been republished cleanly. Pin to verified commits in the interim if you cannot remove the dependency.
  4. Hunt. Check egress logs for connections from build hosts and production boxes to unusual endpoints in the disclosure window. Aikido and Socket published indicators in their writeups.
  5. Audit your trust model. If you rely on Composer tags rather than commit SHAs, a future tag-rewrite attack will hit you the same way. Consider composer.lock pinning to commits, or running a private mirror with content-addressed fetching.

Context

The Laravel-Lang incident is the third high-profile Packagist-resolver attack in eight months and the second one this year that turned the autoload.files mechanism into an unconditional execution sink. The pattern — compromise a maintainer or maintainer-adjacent account, rewrite history, let the package manager do the rest — is becoming a routine playbook against the PHP ecosystem the way it already is against npm and PyPI.

Packagist's quick takedown limited the blast radius for fresh installs, but any team that pulled during the window is the breach, not a near-miss.

Related stories