Your message dated Sat, 11 Jul 2026 10:32:47 +0000
with message-id <[email protected]>
and subject line Released in 13.6
has caused the Debian Bug report #1136642,
regarding trixie-pu: package composer/2.8.8-1+deb13u3
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact [email protected]
immediately.)


-- 
1136642: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1136642
Debian Bug Tracking System
Contact [email protected] with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: [email protected]
Control: affects -1 + src:composer
User: [email protected]
Usertags: pu

Hi,

As agreed with the security team, I’d like to address a GitHub token
leak [CVE-2026-45793] via p-u. The change is just a regex match on code
that may not be used outside of GitHub infrastructure, and the testsuite
is updated to check for it.

[ Checklist ]
  [x] *all* changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in (old)stable
  [x] the issue is verified as fixed in unstable

Cheers,

taffit
diff -Nru composer-2.8.8/debian/changelog composer-2.8.8/debian/changelog
--- composer-2.8.8/debian/changelog	2026-04-15 10:50:08.000000000 +0200
+++ composer-2.8.8/debian/changelog	2026-05-14 10:37:40.000000000 +0200
@@ -1,3 +1,10 @@
+composer (2.8.8-1+deb13u3) trixie; urgency=medium
+
+  * Fix regexp to support new GitHub installation tokens format
+    (GHSA-f9f8-rm49-7jv2) [CVE-2026-45793]
+
+ -- David Prévot <[email protected]>  Thu, 14 May 2026 10:37:40 +0200
+
 composer (2.8.8-1+deb13u2) trixie; urgency=medium
 
   * Fix command injection via malicious Perforce repository definition
diff -Nru composer-2.8.8/debian/patches/0020-ProcessExecutor-mask-GitHub-fine-grained-access-toke.patch composer-2.8.8/debian/patches/0020-ProcessExecutor-mask-GitHub-fine-grained-access-toke.patch
--- composer-2.8.8/debian/patches/0020-ProcessExecutor-mask-GitHub-fine-grained-access-toke.patch	1970-01-01 01:00:00.000000000 +0100
+++ composer-2.8.8/debian/patches/0020-ProcessExecutor-mask-GitHub-fine-grained-access-toke.patch	2026-05-14 10:37:03.000000000 +0200
@@ -0,0 +1,68 @@
+From: Stephan <[email protected]>
+Date: Thu, 21 Aug 2025 10:07:24 +0100
+Subject: ProcessExecutor: mask GitHub fine grained access tokens similar to
+ URL (#12487)
+
+Origin: upstream, https://github.com/composer/composer/commit/af81eac1816effad4fa959eb79b73ba214254540
+---
+ src/Composer/Util/GitHub.php                     | 2 ++
+ src/Composer/Util/ProcessExecutor.php            | 4 ++--
+ src/Composer/Util/Url.php                        | 4 ++--
+ tests/Composer/Test/Util/ProcessExecutorTest.php | 1 +
+ 4 files changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/src/Composer/Util/GitHub.php b/src/Composer/Util/GitHub.php
+index 64ee4f5..c6ad90f 100644
+--- a/src/Composer/Util/GitHub.php
++++ b/src/Composer/Util/GitHub.php
+@@ -23,6 +23,8 @@ use Composer\Pcre\Preg;
+  */
+ class GitHub
+ {
++    public const GITHUB_TOKEN_REGEX = '{^([a-f0-9]{12,}|gh[a-z]_[a-zA-Z0-9_]+|github_pat_[a-zA-Z0-9_]+)$}';
++
+     /** @var IOInterface */
+     protected $io;
+     /** @var Config */
+diff --git a/src/Composer/Util/ProcessExecutor.php b/src/Composer/Util/ProcessExecutor.php
+index 11db709..91a5c40 100644
+--- a/src/Composer/Util/ProcessExecutor.php
++++ b/src/Composer/Util/ProcessExecutor.php
+@@ -483,8 +483,8 @@ class ProcessExecutor
+ 
+         $commandString = is_string($command) ? $command : implode(' ', array_map(self::class.'::escape', $command));
+         $safeCommand = Preg::replaceCallback('{://(?P<user>[^:/\s]+):(?P<password>[^@\s/]+)@}i', static function ($m): string {
+-            // if the username looks like a long (12char+) hex string, or a modern github token (e.g. ghp_xxx) we obfuscate that
+-            if (Preg::isMatch('{^([a-f0-9]{12,}|gh[a-z]_[a-zA-Z0-9_]+)$}', $m['user'])) {
++            // if the username looks like a long (12char+) hex string, or a modern github token (e.g. ghp_xxx, github_pat_xxx) we obfuscate that
++            if (Preg::isMatch(GitHub::GITHUB_TOKEN_REGEX, $m['user'])) {
+                 return '://***:***@';
+             }
+             if (Preg::isMatch('{^[a-f0-9]{12,}$}', $m['user'])) {
+diff --git a/src/Composer/Util/Url.php b/src/Composer/Util/Url.php
+index 32f6134..7e615fe 100644
+--- a/src/Composer/Util/Url.php
++++ b/src/Composer/Util/Url.php
+@@ -110,8 +110,8 @@ class Url
+         $url = Preg::replace('{([&?]access_token=)[^&]+}', '$1***', $url);
+ 
+         $url = Preg::replaceCallback('{^(?P<prefix>[a-z0-9]+://)?(?P<user>[^:/\s@]+):(?P<password>[^@\s/]+)@}i', static function ($m): string {
+-            // if the username looks like a long (12char+) hex string, or a modern github token (e.g. ghp_xxx) we obfuscate that
+-            if (Preg::isMatch('{^([a-f0-9]{12,}|gh[a-z]_[a-zA-Z0-9_]+|github_pat_[a-zA-Z0-9_]+)$}', $m['user'])) {
++            // if the username looks like a long (12char+) hex string, or a modern github token (e.g. ghp_xxx, github_pat_xxx) we obfuscate that
++            if (Preg::isMatch(GitHub::GITHUB_TOKEN_REGEX, $m['user'])) {
+                 return $m['prefix'].'***:***@';
+             }
+ 
+diff --git a/tests/Composer/Test/Util/ProcessExecutorTest.php b/tests/Composer/Test/Util/ProcessExecutorTest.php
+index 28aca39..da27847 100644
+--- a/tests/Composer/Test/Util/ProcessExecutorTest.php
++++ b/tests/Composer/Test/Util/ProcessExecutorTest.php
+@@ -82,6 +82,7 @@ class ProcessExecutorTest extends TestCase
+             ['echo https://foo:[email protected]/', 'echo https://foo:***@example.org/'],
+             ['echo http://[email protected]', 'echo http://[email protected]'],
+             ['echo http://abcdef1234567890234578:[email protected]/', 'echo http://***:***@github.com/'],
++            ['echo http://github_pat_1234567890abcdefghijkl_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVW:[email protected]/', 'echo http://***:***@github.com/'],
+             ["svn ls --verbose --non-interactive  --username 'foo' --password 'bar'  'https://foo.example.org/svn/'", "svn ls --verbose --non-interactive  --username 'foo' --password '***'  'https://foo.example.org/svn/'"],
+             ["svn ls --verbose --non-interactive  --username 'foo' --password 'bar \'bar'  'https://foo.example.org/svn/'", "svn ls --verbose --non-interactive  --username 'foo' --password '***'  'https://foo.example.org/svn/'"],
+         ];
diff -Nru composer-2.8.8/debian/patches/0021-Fix-regexp-to-support-new-GitHub-installation-tokens.patch composer-2.8.8/debian/patches/0021-Fix-regexp-to-support-new-GitHub-installation-tokens.patch
--- composer-2.8.8/debian/patches/0021-Fix-regexp-to-support-new-GitHub-installation-tokens.patch	1970-01-01 01:00:00.000000000 +0100
+++ composer-2.8.8/debian/patches/0021-Fix-regexp-to-support-new-GitHub-installation-tokens.patch	2026-05-14 10:37:03.000000000 +0200
@@ -0,0 +1,148 @@
+From: Philipp Scheit <[email protected]>
+Date: Wed, 13 May 2026 09:00:52 +0200
+Subject: Fix regexp to support new GitHub installation tokens format (#12853)
+
+Origin: upstream, https://github.com/composer/composer/commit/37872360dc9c0f8befc12f741e98db2aa9b1827c
+Bug: https://github.com/composer/composer/security/advisories/GHSA-f9f8-rm49-7jv2
+---
+ src/Composer/IO/BaseIO.php            |  5 +-
+ src/Composer/Util/GitHub.php          |  2 +-
+ tests/Composer/Test/IO/BaseIOTest.php | 99 +++++++++++++++++++++++++++++++++++
+ 3 files changed, 103 insertions(+), 3 deletions(-)
+ create mode 100644 tests/Composer/Test/IO/BaseIOTest.php
+
+diff --git a/src/Composer/IO/BaseIO.php b/src/Composer/IO/BaseIO.php
+index 55ac166..9650c96 100644
+--- a/src/Composer/IO/BaseIO.php
++++ b/src/Composer/IO/BaseIO.php
+@@ -136,9 +136,10 @@ abstract class BaseIO implements IOInterface
+ 
+             // 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.'"');
++            if (!Preg::isMatch('{^[.A-Za-z0-9_-]+$}', $token)) {
++                throw new \UnexpectedValueException('Your github oauth token for '.$domain.' contains invalid characters.');
+             }
++
+             $this->checkAndSetAuthentication($domain, $token, 'x-oauth-basic');
+         }
+ 
+diff --git a/src/Composer/Util/GitHub.php b/src/Composer/Util/GitHub.php
+index c6ad90f..c1cfdfe 100644
+--- a/src/Composer/Util/GitHub.php
++++ b/src/Composer/Util/GitHub.php
+@@ -23,7 +23,7 @@ use Composer\Pcre\Preg;
+  */
+ class GitHub
+ {
+-    public const GITHUB_TOKEN_REGEX = '{^([a-f0-9]{12,}|gh[a-z]_[a-zA-Z0-9_]+|github_pat_[a-zA-Z0-9_]+)$}';
++    public const GITHUB_TOKEN_REGEX = '{^([a-f0-9]{12,}|gh[a-z]_[a-zA-Z0-9_.-]+|github_pat_[a-zA-Z0-9_]+)$}';
+ 
+     /** @var IOInterface */
+     protected $io;
+diff --git a/tests/Composer/Test/IO/BaseIOTest.php b/tests/Composer/Test/IO/BaseIOTest.php
+new file mode 100644
+index 0000000..b899d86
+--- /dev/null
++++ b/tests/Composer/Test/IO/BaseIOTest.php
+@@ -0,0 +1,99 @@
++<?php declare(strict_types=1);
++
++/*
++ * This file is part of Composer.
++ *
++ * (c) Nils Adermann <[email protected]>
++ *     Jordi Boggiano <[email protected]>
++ *
++ * For the full copyright and license information, please view the LICENSE
++ * file that was distributed with this source code.
++ */
++
++namespace Composer\Test\IO;
++
++use Composer\Config;
++use Composer\IO\BufferIO;
++use Composer\Test\TestCase;
++
++class BaseIOTest extends TestCase
++{
++    /**
++     * @dataProvider provideValidGithubTokens
++     */
++    public function testLoadConfigurationAcceptsValidGithubToken(string $token): void
++    {
++        $io = new BufferIO();
++        $config = new Config(false);
++        $config->merge(['config' => ['github-oauth' => ['github.com' => $token]]]);
++
++        $io->loadConfiguration($config);
++
++        $auth = $io->getAuthentication('github.com');
++        self::assertSame($token, $auth['username']);
++        self::assertSame('x-oauth-basic', $auth['password']);
++    }
++
++    /** @return array<string, array{string}> */
++    public static function provideValidGithubTokens(): array
++    {
++        return [
++            'legacy 40-hex PAT' => ['8a7f2c1bdc4e9f06a3b7c2e9d4f1a8b6c5d7e0f2'],
++            'ghp_ flat token' => ['ghp_n3K9wQ2eL5bV8mY1pX4cZ7aR0fT6sH3uJ8oI'],
++            'gho_ flat token' => ['gho_M2pQ7vR4xL9eK6bN1cT8aZ0sJ3wY5fH7uG2d'],
++            'ghu_ flat token' => ['ghu_R5tY8wA1xC4eK7bN0pV3mL6sH9uJ2gD5fQ8z'],
++            'ghs_ flat token' => ['ghs_K7bN3pV5mL8eR2tY9wA1xC4sH6uJ0gD3fQ8z'],
++            'ghr_ flat token' => ['ghr_X9aZ2sJ5wY8fH1uG4dR7bN0pV3mL6eK2tQ5c'],
++            // shivammathur/setup-php style: ghs_<id>_<base64url>.<base64url>.<base64url>
++            // base64url alphabet includes '-' which the old regex rejected
++            'ghs_ structured installation token (jwt body)' => [
++                'ghs_1234567890_eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJjb21wb3NlciJ9.aB-cDef_GHIjkl-mnoPQR0123456',
++            ],
++            'github_pat_ fine-grained PAT' => [
++                'github_pat_11ABCDEFG0aB1cD2eF3gH4_n3K9wQ2eL5bV8mY1pX4cZ7aR0fT6sH3uJ8oI2pQ7vR4xL9eK6bN',
++            ],
++        ];
++    }
++
++    /**
++     * @dataProvider provideUrlBreakingGithubTokens
++     */
++    public function testLoadConfigurationRejectsTokenWithUrlBreakingCharacters(string $token, string $offending): void
++    {
++        $io = new BufferIO();
++        $config = new Config(false);
++        $config->merge(['config' => ['github-oauth' => ['github.com' => $token]]]);
++
++        try {
++            $io->loadConfiguration($config);
++            self::fail('Expected loadConfiguration to reject token containing '.$offending);
++        } catch (\UnexpectedValueException $e) {
++            // Defect #1: the rejected token must not be echoed back into the
++            // exception message — Symfony Console renders it to stderr and CI
++            // log shippers / GitHub Actions secret masking do not reliably
++            // strip it from the framed error block.
++            self::assertStringNotContainsString(
++                $token,
++                $e->getMessage(),
++                'Exception message must not leak the rejected token value.'
++            );
++        }
++    }
++
++    /** @return array<string, array{string, string}> */
++    public static function provideUrlBreakingGithubTokens(): array
++    {
++        return [
++            'contains @ (userinfo separator)' => ['[email protected]', '@'],
++            'contains : (basic-auth user:pass split)' => ['ghp_AAAA:extra', ':'],
++            'contains / (path separator)' => ['ghp_AAA/BBB', '/'],
++            'contains backslash' => ['ghp_AAA\\BBB', '\\'],
++            'contains ? (query separator)' => ['ghp_AAA?x=1', '?'],
++            'contains # (fragment)' => ['ghp_AAA#frag', '#'],
++            'contains space' => ['ghp_AAA BBB', 'space'],
++            'contains tab' => ["ghp_AAA\tBBB", 'tab'],
++            'contains CR' => ["ghp_AAA\rBBB", 'CR'],
++            'contains LF (header injection)' => ["ghp_AAA\nX-Evil: 1", 'LF'],
++        ];
++    }
++}
diff -Nru composer-2.8.8/debian/patches/0022-Modernize-PHPUnit-syntax.patch composer-2.8.8/debian/patches/0022-Modernize-PHPUnit-syntax.patch
--- composer-2.8.8/debian/patches/0022-Modernize-PHPUnit-syntax.patch	1970-01-01 01:00:00.000000000 +0100
+++ composer-2.8.8/debian/patches/0022-Modernize-PHPUnit-syntax.patch	2026-05-14 10:37:03.000000000 +0200
@@ -0,0 +1,38 @@
+From: =?utf-8?q?David_Pr=C3=A9vot?= <[email protected]>
+Date: Fri, 29 Aug 2025 08:31:05 +0200
+Subject: Modernize PHPUnit syntax
+
+---
+ tests/Composer/Test/IO/BaseIOTest.php | 9 +++------
+ 1 file changed, 3 insertions(+), 6 deletions(-)
+
+diff --git a/tests/Composer/Test/IO/BaseIOTest.php b/tests/Composer/Test/IO/BaseIOTest.php
+index b899d86..e22d8ea 100644
+--- a/tests/Composer/Test/IO/BaseIOTest.php
++++ b/tests/Composer/Test/IO/BaseIOTest.php
+@@ -15,12 +15,11 @@ namespace Composer\Test\IO;
+ use Composer\Config;
+ use Composer\IO\BufferIO;
+ use Composer\Test\TestCase;
++use PHPUnit\Framework\Attributes\DataProvider;
+ 
+ class BaseIOTest extends TestCase
+ {
+-    /**
+-     * @dataProvider provideValidGithubTokens
+-     */
++    #[DataProvider('provideValidGithubTokens')]
+     public function testLoadConfigurationAcceptsValidGithubToken(string $token): void
+     {
+         $io = new BufferIO();
+@@ -55,9 +54,7 @@ class BaseIOTest extends TestCase
+         ];
+     }
+ 
+-    /**
+-     * @dataProvider provideUrlBreakingGithubTokens
+-     */
++    #[DataProvider('provideUrlBreakingGithubTokens')]
+     public function testLoadConfigurationRejectsTokenWithUrlBreakingCharacters(string $token, string $offending): void
+     {
+         $io = new BufferIO();
diff -Nru composer-2.8.8/debian/patches/series composer-2.8.8/debian/patches/series
--- composer-2.8.8/debian/patches/series	2026-04-15 10:50:08.000000000 +0200
+++ composer-2.8.8/debian/patches/series	2026-05-14 10:37:03.000000000 +0200
@@ -17,3 +17,6 @@
 0017-Merge-commit-from-fork.patch
 0018-Merge-commit-from-fork.patch
 0019-Merge-commit-from-fork.patch
+0020-ProcessExecutor-mask-GitHub-fine-grained-access-toke.patch
+0021-Fix-regexp-to-support-new-GitHub-installation-tokens.patch
+0022-Modernize-PHPUnit-syntax.patch

Attachment: signature.asc
Description: PGP signature


--- End Message ---
--- Begin Message ---
Version: 13.6

This update was released as part of 13.6.

--- End Message ---

Reply via email to