Composer token leak risk: update before CI logs bite

A GitHub token format change exposed a Composer error path that could print Actions tokens into CI logs. PHP teams should update Composer and review recent

2026-05-13 GIGATAP Team #security
#Composer#GitHub Actions#supply chain security

What happened#

Packagist is urging PHP projects to update Composer after a GitHub token format change caused some GitHub Actions tokens to be exposed in CI logs.

The issue affects Composer versions before the newly released fixes. Packagist says Composer 2.9.8, 2.2.28 LTS, and 1.10.28 address the problem. The vulnerable behavior occurred when Composer rejected a GitHub Actions-issued value or GitHub App installation token during validation, then printed the full token value to stderr.

The trigger was not a classic malicious package event. It was a compatibility failure between Composer’s token validation logic and GitHub’s rollout of a new token format. GitHub announced on April 24 that newly issued GitHub App installation tokens would move to a longer, variable-length format. The rollout was scheduled to begin April 27 and continue over the following weeks.

One detail mattered: the new format included a hyphen. Composer’s previous validation regex did not allow that character. When a workflow supplied one of these new tokens, Composer could reject it as invalid. In some cases, the resulting error output could include the token itself.

That is the sensitive part. CI logs are often easier to reach than secret stores. They are copied, indexed, retained, and reviewed by more people and tools. A token printed into logs is no longer just an environment secret. It becomes an artifact.

Who is exposed#

The main risk is for PHP projects running Composer inside GitHub Actions, especially workflows that configure Composer authentication using GitHub-provided tokens or GitHub App installation tokens.

Packagist says the issue can occur through common GitHub Actions setups, including workflows where setup actions register authentication into Composer. The source material does not identify a single universal workflow pattern that guarantees exposure. The condition to look for is narrower: Composer running in Actions, receiving a token in the new format, failing validation, and printing that value to stderr.

GitHub has since rolled back the token format change, according to Packagist co-founder Nils Adermann. That reduces the immediate chance of new leaks caused by this rollout. It does not make the issue safe to ignore.

Packagist’s May 13 update says it is no longer necessary to immediately disable GitHub Actions. The rollback gives the ecosystem time to update Composer before GitHub attempts a new rollout of the token format. GitHub is also looking into improvements to secrets masking, which could reduce the chance that accidentally printed credentials remain visible in logs.

That said, the practical exposure window depends on the token type and runner setup.

  • GitHub-hosted runner tokens usually expire when the job ends, or after a maximum of 6 hours.
  • For self-hosted runners, a leaked token may remain valid for up to 24 hours after issuance.
  • GitHub App installation tokens may have different scopes and should be reviewed based on the permissions requested.

Packagist.org itself is not affected, according to the report. The public registry does not use a GitHub App and does not run Composer against GitHub App installation tokens. Private Packagist has already applied the Composer fix and audited update logs, with no token exposure found.

What changed in Composer#

The fixed Composer releases remove the rejected token value from the error message. They also relax the validation character set so Composer accepts the new GitHub token format.

Teams should update to Composer 2.9.8 or Composer 2.2.28 LTS immediately. Composer 1.10.28 also includes the fix for legacy users, though Packagist recommends moving to Composer 2.x where possible.

This is a small code-path fix with a large operational consequence. The failure mode was not that Composer created a new secret. It was that Composer handled a rejected secret as if it were safe diagnostic text.

That pattern is common. Validation failures often produce verbose errors. Verbose errors are useful during development. In CI, they can become durable leaks.

The other important point is GitHub’s guidance: treat tokens as opaque strings. Do not validate them against hardcoded assumptions about length, prefix, or character set unless the platform explicitly gives a stable contract for doing so. Token formats change. Security tooling, build tooling, and package managers need to fail closed without printing the credential that failed validation.

What teams should do now#

The first action is straightforward: update Composer in any workflow that runs Composer inside GitHub Actions.

Use Composer 2.9.8 or 2.2.28 LTS. If a project is still on Composer 1.x, use 1.10.28 as the immediate fix, then plan a migration to Composer 2.x where possible.

After updating, review recent GitHub Actions logs for failed Composer runs during the rollout window. The source does not provide a universal date range beyond GitHub’s announced rollout beginning April 27 and Packagist’s May 13 update. Teams should focus on jobs that ran Composer with GitHub authentication configured, especially jobs that failed with token validation or authentication errors.

If a token appears in logs, treat it as exposed.

Practical checks:

  • Delete or restrict affected log output where possible.
  • Rotate any long-lived credential that may have been printed.
  • Review GitHub App installation token permissions and related app activity.
  • Check for unexpected repository, package, or workflow activity tied to the exposed credential.
  • Confirm self-hosted runner behavior separately, because token lifetime and log retention may differ from GitHub-hosted runners.

For many GitHub-hosted jobs, the token may already have expired. That lowers the probability of live abuse. It does not remove the need to review logs. Expired credentials can still reveal workflow structure, permission design, and operational habits. In some cases, teams may not know whether the printed value was short-lived until they inspect the workflow.

What not to overclaim#

This report does not say Packagist.org was compromised. It says Packagist.org is not affected by this issue.

It also does not establish that every PHP project using Composer in GitHub Actions leaked a token. The risk depends on token format, Composer version, workflow configuration, and whether the affected error path was reached.

There is also no basis in the provided source to claim active exploitation. The incident is serious because credentials may have been printed into logs, not because a confirmed attacker campaign is described here.

The clean reading is this: a platform token format changed, a package manager rejected the new shape, and an error path could disclose the rejected secret. GitHub rolled the format change back. Composer shipped fixes. Teams still need to update and inspect logs because rollback does not erase artifacts already written.

The broader lesson#

This is a supply-chain security issue, but not in the usual “malicious dependency” sense. It sits in the glue layer between package management, CI, token issuance, and logs.

Modern build pipelines rely on short-lived credentials. That model only works if tools treat those credentials as secrets at every stage, including error handling. A token should not become printable just because a regex did not recognize its new shape.

The durable fix is not only “patch Composer,” though that is the urgent step. The larger fix is to design CI tooling around opaque credentials, conservative logging, and explicit redaction. Token formats will keep changing. Build systems should not leak when they do.