Laravel-Lang Composer tag-rewrite Supply Chain Attack
The post Laravel-Lang Composer tag-rewrite Supply Chain Attack appeared first on Mend.On 2026-0 2026-5-23 17:17:4 Author: securityboulevard.com(查看原文) 阅读量:19 收藏

The post Laravel-Lang Composer tag-rewrite Supply Chain Attack appeared first on Mend.

On 2026-05-22, an attacker rewrote every repository tag across four Composer packages in the Laravel-Lang ecosystem to point at malicious commits. The affected packages are laravel-lang/lang, laravel-lang/attributes, laravel-lang/http-statuses, and laravel-lang/actions. The rewrite took place on 2026-05-22 into the early hours of 2026-05-23. Every malicious commit makes the same two-file change: one entry added to composer.json, and one new file at src/helpers[.]php. This article walks through both files as they actually exist in a poisoned tree.

The compromise

The malicious commits in all four repositories share the same git author identity, Your Name <[email protected]>. The commits are not reachable from any branch in the upstream repositories; only the rewritten tags point to them. The combination of the shared author identity, the orphan-commit topology, and the compressed rewrite window across four repositories is consistent with one operator running through the four targets in sequence.

The composer.json change

The poisoned manifest’s autoload block contains two entries:

"autoload": {
   "psr-4": {
       "LaravelLang\\Lang\\": "src/"
   },
   "files": [
       "src/helpers.php"
   ]
}

The PSR-4 entry maps the package’s LaravelLang\Lang\ namespace to src/. The "files" entry is the attack vector.

Composer’s autoload.files directive is documented to load every listed file immediately when an application requires vendor/autoload.php. Unlike PSR-4 entries, which are lazy and only load classes on first reference, autoload.files entries are eager: they execute the moment the autoloader is bootstrapped. In a Laravel application this happens on every HTTP request boot. In a Composer-using CLI tool it happens on every command invocation. In a CI workflow it happens the first time any step touches the project’s autoload.

Inside helpers.php

The dropper opens with two decoy functions, laravel_lang_locale() and laravel_lang_fallback(), that wrap Laravel’s config() and return the application locale. The malicious behavior lives in an anonymous closure guarded by a LARAVEL_LANG_HELPERS define-check. The closure runs once per host, and the once-enforcement is a marker file:

Laravel-Lang Composer tag-rewrite Supply Chain Attack - image

The marker filename is an MD5 over three values: the install directory, the host’s network name returned by php_una‌me('n'), and the inode of helpers.php itself. The closure returns early on a second invocation, so the dropper fires exactly once per vendor/ tree per host.

The C2 host is kept out of plain-text scans by reconstructing it from a byte array:

Laravel-Lang Composer tag-rewrite Supply Chain Attack - image 1

The byte array spells flipboxstudio[.]info.

The fetcher tries file_get_‌contents first with a custom stream context, then falls back to libcurl if the first returns less than 50 bytes. Both transports set verify_peer => false, CURLOPT_SSL_VERIFYPEER => false, and a spoofed Mozilla/5.0 User-Agent. The 50-byte minimum is the dropper’s signal-quality check: it tolerates a transport failure but rejects an empty or near-empty response.

If the fetch returns content, the dropper writes the response to a random filename under sys_get_temp‌_dir()/.laravel_locale/ (bin2hex(random_bytes(6)) produces a 12-hex-character name) and branches on OS for launch. On Linux and macOS the launch is ex‌ec("php \"$f\" > /dev/null 2>&1 &"). On Windows the dropper writes a 4-byte-randomized .vbs shim that calls WScript.‌Shell.Run with a non-blocking flag, invoked from cscript //nologo //b. Every filesystem and network call in the closure uses PHP’s @ error-suppression operator, so no warning or stack trace reaches PHP-FPM, the web server, or error_log.

The full closure is roughly fifty lines of PHP. By the time control returns from vendor/autoload.php, the stage-two PHP is already running detached in the background.

What runs next

Analysis of the stage-two payload served from hxxps://flipboxstudio[.]info/payload shows a PHP credential stealer targeting cloud, container, and developer-machine credentials: EC2 instance metadata at 169.254.169.254, Kubernetes service-account tokens at /var/run/secrets/, HashiCorp Vault, Jenkins master.key and credentials.xml, Linux /proc/<pid>/environ and /cmdline, and Chrome v127+ App-Bound Encryption via a dropped DebugChromium.exe. The harvested data is XOR-encrypted with the key k9X2mP7vL4nQ8wR1 and POSTed to hxxps://flipboxstudio[.]info/exfil.

Indicators of compromise

Category Indicator
C2 domain flipboxstudio[.]info
Stage-one URL hxxps://flipboxstudio[.]info/payload
Stage-two exfil URL hxxps://flipboxstudio[.]info/exfil
Drop directory <sys_get_temp‌_dir>/.laravel_locale/
Stage-two PHP filename ^[0-9a-f]{12}\.php$
Windows launcher filename ^[0-9a-f]{8}\.vbs$
Windows stage-three binary DebugChromium.exe
Cloud-metadata egress Outbound to 169.254.169.254 from a PHP process
In-process constant LARAVEL_LANG_HELPERS
composer.json indicator "files": ["src/helpers.php"] entry under autoload
Affected packages laravel-lang/lang, laravel-lang/attributes, laravel-lang/http-statuses, laravel-lang/actions
Rewrite window 2026-05-22 into 2026-05-23
Malicious commit author Your Name <[email protected]>
  1. Block flipboxstudio[.]info at DNS and HTTPS proxy layers, then investigate.
  2. Audit composer.lock against upstream history. For each source.reference SHA recorded under laravel-lang/lang, laravel-lang/attributes, laravel-lang/http-statuses, or laravel-lang/actions, look the SHA up in the upstream repository and check the commit author. Any commit authored by Your Name <[email protected]> is a poisoned install. Lockfiles whose pinned SHAs pre-date 2026-05-22 and are reachable from upstream branch history are safe, provided no composer update has run since.
  3. Reinstall against a known-good commit. Tag-based version constraints in composer.json resolve to whatever the rewritten tag now points at, so re-running composer install against a tag constraint is not sufficient. Pin each affected laravel-lang/* dependency to a commit SHA that pre-dates 2026-05-22 and is reachable from upstream branch history, then run composer update <package> to refetch. Confirm afterwards that vendor/laravel-lang/*/composer.json no longer contains the "files": ["src/helpers.php"] autoload entry and that src/helpers.php is no longer in the package tree.
  4. Remove working artifacts. Delete <sys_get_temp‌_dir>/.laravel_locale/ on every affected host.
  5. Rotate credentials. On CI runners that ran the install, rotate every cloud key, registry token, and deploy key the workflow had access to, and audit the job’s GitHub API activity. On developer machines, treat the host as fully compromised.
  6. Going forward, treat the lockfile’s pinned commit SHAs as the source of truth and verify each SHA is reachable from the upstream repository’s branch history before deploying. Tag-based resolution alone does not detect the kind of tag rewrite seen in this incident.

Mend.io coverage

Mend.io has issued an MSC covering all four affected Laravel-Lang Composer packages:

  • MSC-2026-5762

References

https://socket.dev/blog/laravel-lang-compromise

Aikido Security: https://www.aikido.dev/blog/supply-chain-attack-targets-laravel-lang-packages-with-credential-stealer

Laravel-Lang/attributes issue #1085: https://github.com/Laravel-Lang/attributes/issues/1085

StepSecurity: https://www.stepsecurity.io/blog/laravel-lang-supply-chain-attack

*** This is a Security Bloggers Network syndicated blog from Mend authored by Alina Podoba. Read the original post at: https://www.mend.io/blog/laravel-lang-composer-tag-rewrite-supply-chain-attack/


文章来源: https://securityboulevard.com/2026/05/laravel-lang-composer-tag-rewrite-supply-chain-attack/
如有侵权请联系:admin#unsafe.sh