Severity by source
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Primary rating from Vendor (https://github.com/composer/composer) · only source for this CVE.
CVSS VectorVendor: https://github.com/composer/composer
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Lifecycle Timeline
2DescriptionCVE.org
Summary
Composer leaks the full contents of tokens configured as GitHub OAuth tokens if they do not match Composer's expected format for such tokens to stderr. GitHub has introduced a new format for GitHub Actions GITHUB_TOKEN values. These tokens are validated in the same way by Composer on GitHub Actions. The new format including a - (hyphen) fails Composer's validation and leads to disclosure of the GITHUB_TOKEN in logs.
Many widely-used Actions (e.g. shivammathur/setup-php) auto-register GITHUB_TOKEN into composer's global auth.json, so the leak triggers without any unusual user configuration.
GitHub Actions tokens expire when the associated job finishes, and they are scoped to the respective repository only. So in most regular cases the Composer validation, which errors while leaking the token, also immediately ends the job, expiring the token immediately. Tokens expire at the very latest after 6 hours on GitHub-hosted runners. If you use self-hosted runner, expiration is at most 24 hours after creation. The new token format is being rolled out gradually, so not all repositories are affected yet, but will be soon.
Classic ghp_ PATs are not affected by the regex bug per se, but the same leak primitive applies to any future credential that fails validation for any reason.
Details
When a GitHub token fails regular expression validation of the character set, the rejected token is interpolated verbatim into the UnexpectedValueException message thrown by Composer\IO\BaseIO::loadConfiguration(), which Symfony Console then prints. Validation reliably fails for any token containing a - (hyphen), which includes the modern ghs_<id>_<base64url-JWT> GitHub App installation token format, the same format used by GitHub Actions' built-in GITHUB_TOKEN and by actions/create-github-app-token.
Severity: medium. Pre-conditions are common in real-world CI. Practical blast radius is bounded by the leaked credential's scope and TTL (short for a workflow GITHUB_TOKEN, longer for App-minted tokens or user-issued credentials that happen to contain -).
Vulnerable code, src/Composer/IO/BaseIO.php (line 139 on main, line 143 on 2.8.x), inside loadConfiguration():
// allowed chars for GH tokens are from https://github.blog/changelog/2021-03-04-authentication-token-format-updates/
// plus dots which were at some point used for GH app integration tokens
if (!Preg::isMatch('{^[.A-Za-z0-9_]+$}', $token)) {
throw new \UnexpectedValueException(
'Your github oauth token for '.$domain.' contains invalid characters: "'.$token.'"'
);
}Three issues combine to produce the leak:
- The rejected token is interpolated into the exception message. The exception bubbles up to Symfony Console's default error renderer, which writes it to stderr. Any environment that captures stderr (CI logs, log shippers, monitoring, support transcripts) now has the raw token.
- The validation regex
^[.A-Za-z0-9_]+$does not permit-. GitHub's currentghs_<numeric-id>_<base64url-JWT>structured installation tokens routinely contain-, because base64url (RFC 4648 §5) uses-and_as URL-safe replacements for+and/. The regex was chosen in 2021 on the understanding that GitHub tokens use only[A-Za-z0-9_]plus.. - Detection / mitigation in upstream platforms is unreliable. GitHub Actions' built-in secret masker matches registered values as exact substrings. When the exception message is rendered by Symfony Console it may wrap, embed in
In BaseIO.php line N:framing, or interleave with ANSI control sequences. So the masker does not redact, and the plaintext token reaches the log.
AnalysisAI
Sensitive token disclosure in Composer (PHP dependency manager) versions prior to 1.10.28, 2.2.28, and 2.9.8 causes GitHub Actions GITHUB_TOKEN values to be written verbatim to stderr/CI logs whenever the token contains characters outside Composer's hardcoded validation regex. The new GitHub Actions token format (ghs_<id>_<base64url-JWT>) includes hyphens, which fail Composer's ^[.A-Za-z0-9_]+$ check and trigger an UnexpectedValueException that interpolates the raw token into its message. No public exploit identified at time of analysis, but the leak triggers automatically without unusual configuration on any pipeline using common actions like shivammathur/setup-php that auto-register GITHUB_TOKEN into Composer's auth.json.
Technical ContextAI
Composer is the de-facto dependency manager for PHP and is routinely invoked inside CI pipelines, including GitHub Actions. The root cause is CWE-200 (Exposure of Sensitive Information): in src/Composer/IO/BaseIO.php::loadConfiguration(), tokens registered for GitHub OAuth domains are validated against ^[.A-Za-z0-9_]+$, a regex written in 2021 around GitHub's then-current ghp_/gho_ format. When validation fails, the offending token is concatenated directly into an UnexpectedValueException message that Symfony Console then prints to stderr. GitHub has rolled out a new structured installation/Actions token format (ghs_<numeric-id>_<base64url-JWT>) that uses base64url alphabet (RFC 4648 §5), which includes - and _ - the hyphen fails the regex. GitHub Actions' built-in secret masker compares registered secrets as exact substrings, but Symfony Console wraps lines, prepends In BaseIO.php line N: framing, and interleaves ANSI escapes, so the plaintext token slips past redaction. CPE data (pkg:composer/composer_composer) confirms the upstream Composer package is the only affected component.
RemediationAI
Vendor-released patches: upgrade Composer to 2.9.8 (for 2.3.x-2.9.x branch), 2.2.28 (for 2.0.x-2.2.x LTS branch), or 1.10.28 (for legacy 1.x branch), per the GHSA-f9f8-rm49-7jv2 advisory at https://github.com/composer/composer/security/advisories/GHSA-f9f8-rm49-7jv2. In CI pipelines this typically means pinning a fixed Composer version in setup actions (e.g., shivammathur/setup-php with tools: composer:2.9.8). Until upgraded, the most effective compensating control is to stop auto-registering GITHUB_TOKEN into Composer's auth.json - either unset COMPOSER_AUTH/disable the action input that injects it, or restrict Composer invocations to public package fetches that do not require authentication; the trade-off is that private Packagist or rate-limited GitHub API fetches will fail. Where token use is unavoidable, rotate any potentially exposed GITHUB_TOKEN-derived credentials (especially App installation tokens minted via actions/create-github-app-token), make affected workflow runs and logs private, and scrub log retention. Generic secret-masker reliance is insufficient because Symfony Console line-wrapping and ANSI framing defeat substring matching.
sapi/cgi/cgi_main.c in PHP before 5.3.12 and 5.4.x before 5.4.2, when configured as a CGI script (aka php-cgi), does not
(1) boardData102.php, (2) boardData103.php, (3) boardDataJP.php, (4) boardDataNA.php, and (5) boardDataWW.php in Netgear
ProjectSend versions prior to r1720 are affected by an improper authentication vulnerability. Rated critical severity (C
Roundcube Webmail contains a critical PHP object deserialization vulnerability (CVE-2025-49113, CVSS 9.9) that allows au
Util/PHP/eval-stdin.php in PHPUnit before 4.8.28 and 5.x before 5.6.3 allows remote attackers to execute arbitrary PHP c
Palo Alto Networks PAN-OS management web interface contains an authentication bypass allowing unauthenticated attackers
Nagios XI version xi-5.7.5 is affected by OS command injection. Rated high severity (CVSS 8.8), this vulnerability is re
Nagios XI version xi-5.7.5 is affected by OS command injection. Rated high severity (CVSS 8.8), this vulnerability is re
The get_referers function in /opt/ws/bin/sblistpack in Sophos Web Appliance before 3.7.9.1 and 3.8 before 3.8.1.1 allows
The Backup Migration plugin for WordPress is vulnerable to Remote Code Execution in all versions up to, and including, 1
NetAlertX (formerly PiAlert) versions 23.01.14 through 24.x before 24.10.12 allow unauthenticated command injection thro
The GiveWP - Donation Plugin and Fundraising Platform plugin for WordPress is vulnerable to PHP Object Injection in all
Same weakness CWE-200 – Information Exposure
View allSame technique Information Disclosure
View allShare
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-44723
GHSA-f9f8-rm49-7jv2