Cybersecurity

CVE-2026-45793: The PHP Ecosystem Just Dodged a 14-Hour Supply-Chain Catastrophe — Is Your Composer Version Right?

2026.05.18 · 36 views
CVE-2026-45793: The PHP Ecosystem Just Dodged a 14-Hour Supply-Chain Catastrophe — Is Your Composer Version Right?

A token-validation regex Composer wrote back in 2021 nearly leaked every PHP project's GITHUB_TOKEN into public CI logs

At 22:00 UTC on May 12, GitHub quietly rolled out a new structured format for `GITHUB_TOKEN`, introducing a hyphen `-` as a section separator. From GitHub's perspective this was a routine improvement. For the PHP ecosystem, it tripped a five-year-old landmine no one knew was there: Composer's 2021-era token validation regex rejects the `-` character. When validation fails, Composer prints the full token contents to stderr. In GitHub Actions, stderr is captured into the public build log by default.


For the next 14 hours, every PHP project whose CI ran `composer install`, `composer update`, or any Composer subcommand that touches the GitHub API would print a plaintext `GITHUB_TOKEN` into its build log. If the workflow ran on `push`, `pull_request_target`, or `schedule`, that log was readable by anyone in a public repo.


The issue was assigned CVE-2026-45793, CVSS 7.5.


1. Why Those 14 Hours Nearly Became the Biggest Supply-Chain Incident in PHP History


`GITHUB_TOKEN` is the token GitHub Actions injects into a workflow by default; its default permissions usually include `contents: write` and `pull-requests: write`. For an attacker, a write-enabled token means:


  • Push new commits and tags to the repo.
  • Publish new releases.
  • For Packagist packages linked to GitHub releases, directly poison the next published version.

If an attacker had been monitoring popular PHP project build logs during the window (legal on public repos), the volume of harvested tokens could easily reach the tens of thousands. Push a malicious commit to one widely-depended package — monolog, guzzle, any Symfony component — and you don't need phishing or social engineering. Every downstream `composer install` running in a developer machine or a production build pulls poisoned code.


GitHub temporarily rolled back the token format change at 14:30 UTC on May 13. Composer patched three LTS lines simultaneously: 2.9.8, 2.2.28, and 1.10.28. But that token format change is coming back — this is just a grace window for the PHP ecosystem to upgrade.


2. Five Things to Do Right Now


Don't wait for the next GitHub rollout to scramble. Today:


  1. Upgrade Composer: pin CI to `composer self-update 2.9.8` or above. In Dockerfiles change `composer:2` to `composer:2.9.8` explicitly.
  2. Rotate any potentially leaked tokens: GitHub → Settings → Developer settings → Personal access tokens — revoke every PAT used in PHP-project CI between May 12 and 13.
  3. Audit Actions logs: for any build between May 12–13, grep for strings starting with `gho_`, `ghs_`, or `ghp_`. Anything you find, treat as leaked.
  4. Delete public build logs: in the Actions UI, delete the entire workflow run for any compromised build. Note: deletion does not recover copies attackers may have already harvested.
  5. Add a permanent guardrail: put a `permissions:` block at the top of every GitHub Actions workflow with `GITHUB_TOKEN` defaulted to `read-all`, and have individual jobs request write only when needed. This is the only structural fix that limits damage when the next leak happens.

3. Additional Checks for Laravel / Symfony Teams


  • Private package repos (Satis, Private Packagist, GitHub Packages): rotate authentication tokens if there's any chance they were logged.
  • Composer scripts in `post-install-cmd`: don't echo tokens or environment variables for debug — those prints also land in the build log.
  • Laravel Envoyer / Forge deploy hooks: if a deploy is triggered from GitHub Actions, audit any intermediate variables that might have been logged.
  • Symfony Flex recipes: upstream wasn't compromised, but make `composer audit` a standing CI step.

4. Why This Incident Belongs in Your Security SOP


The most disturbing thing about this incident: nobody did anything wrong. GitHub shipping a more secure token format is good. Composer enforcing strict token validation is good. Printing validation failures to stderr for debugging is good. Three correct decisions, stacked together, opened a 14-hour global supply-chain window.


This is the new shape of supply-chain attacks in 2026 — the attack surface isn't in your code, it's in the seams where your tools, your platforms, and your default settings interact.


My Take


If you're a PHP/Laravel agency, three actions are non-negotiable:


First, add "Composer version" to the monthly SRE checklist you give every client. It used to be nice-to-have; now it's a contractual responsibility.


Second, on every client repo, add a `permissions:` read-only default to GitHub Actions workflows today. Write a migration commit template and you can process twenty repos in half an hour.


Third, learn how to explain incidents like this — incidents where nobody did anything wrong but the whole world almost burned — to your clients. Clients tend to assume "we didn't get hacked, so we're fine." You need to make them feel "we got lucky this time; we are not protected by design." Agencies that can communicate that distinction earn the right to raise their rates.


Sources


Cybersecurity Back to Blog