Package: release.debian.org
Severity: normal
Tags: bookworm
X-Debbugs-Cc: [email protected]
Control: affects -1 + src:composer
User: [email protected]
Usertags: pu

[ Same as #1124354 for trixie, with a smaller diff. ]

Hi,

As agreed with the security team, I’d like to fix CVE-2025-67746 in a
point release rather than a DSA since it mostly fixes a display issue.

[ 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

Regards,

taffit
diff -Nru composer-2.5.5/debian/changelog composer-2.5.5/debian/changelog
--- composer-2.5.5/debian/changelog	2024-06-14 08:01:19.000000000 +0200
+++ composer-2.5.5/debian/changelog	2025-12-30 17:01:22.000000000 +0100
@@ -1,3 +1,10 @@
+composer (2.5.5-1+deb12u3) bookworm; urgency=medium
+
+  * Backport fix from composer 2.2.26:
+    Fixed ANSI sequence injection [CVE-2025-67746]
+
+ -- David Prévot <[email protected]>  Tue, 30 Dec 2025 17:01:22 +0100
+
 composer (2.5.5-1+deb12u2) bookworm-security; urgency=medium
 
   * Include security fixes from 2.7.7:
diff -Nru composer-2.5.5/debian/patches/0018-Merge-commit-from-fork.patch composer-2.5.5/debian/patches/0018-Merge-commit-from-fork.patch
--- composer-2.5.5/debian/patches/0018-Merge-commit-from-fork.patch	1970-01-01 01:00:00.000000000 +0100
+++ composer-2.5.5/debian/patches/0018-Merge-commit-from-fork.patch	2025-12-30 17:00:22.000000000 +0100
@@ -0,0 +1,122 @@
+From: Jordi Boggiano <[email protected]>
+Date: Tue, 30 Dec 2025 13:18:16 +0100
+Subject: Merge commit from fork
+
+Origin: upstream, https://github.com/composer/composer/commit/1d40a95c9d39a6b7f80d404ab30336c586da9917
+Bug: https://github.com/composer/composer/security/advisories/GHSA-59pp-r3rg-353g
+Bug-Debian: https://security-tracker.debian.org/tracker/CVE-2025-67746
+---
+ src/Composer/IO/ConsoleIO.php | 46 ++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 41 insertions(+), 5 deletions(-)
+
+diff --git a/src/Composer/IO/ConsoleIO.php b/src/Composer/IO/ConsoleIO.php
+index 8ecea42..16d285c 100644
+--- a/src/Composer/IO/ConsoleIO.php
++++ b/src/Composer/IO/ConsoleIO.php
+@@ -12,6 +12,7 @@
+ 
+ namespace Composer\IO;
+ 
++use Composer\Pcre\Preg;
+ use Composer\Question\StrictConfirmationQuestion;
+ use Symfony\Component\Console\Helper\HelperSet;
+ use Symfony\Component\Console\Helper\ProgressBar;
+@@ -120,6 +121,8 @@ class ConsoleIO extends BaseIO
+      */
+     public function write($messages, bool $newline = true, int $verbosity = self::NORMAL)
+     {
++        $messages = self::sanitize($messages);
++
+         $this->doWrite($messages, $newline, false, $verbosity);
+     }
+ 
+@@ -128,6 +131,8 @@ class ConsoleIO extends BaseIO
+      */
+     public function writeError($messages, bool $newline = true, int $verbosity = self::NORMAL)
+     {
++        $messages = self::sanitize($messages);
++
+         $this->doWrite($messages, $newline, true, $verbosity);
+     }
+ 
+@@ -252,7 +257,7 @@ class ConsoleIO extends BaseIO
+     {
+         /** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
+         $helper = $this->helperSet->get('question');
+-        $question = new Question($question, $default);
++        $question = new Question(self::sanitize($question), is_string($default) ? self::sanitize($default) : $default);
+ 
+         return $helper->ask($this->input, $this->getErrorOutput(), $question);
+     }
+@@ -264,7 +269,7 @@ class ConsoleIO extends BaseIO
+     {
+         /** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
+         $helper = $this->helperSet->get('question');
+-        $question = new StrictConfirmationQuestion($question, $default);
++        $question = new StrictConfirmationQuestion(self::sanitize($question), is_string($default) ? self::sanitize($default) : $default);
+ 
+         return $helper->ask($this->input, $this->getErrorOutput(), $question);
+     }
+@@ -276,7 +281,7 @@ class ConsoleIO extends BaseIO
+     {
+         /** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
+         $helper = $this->helperSet->get('question');
+-        $question = new Question($question, $default);
++        $question = new Question(self::sanitize($question), is_string($default) ? self::sanitize($default) : $default);
+         $question->setValidator($validator);
+         $question->setMaxAttempts($attempts);
+ 
+@@ -290,7 +295,7 @@ class ConsoleIO extends BaseIO
+     {
+         /** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
+         $helper = $this->helperSet->get('question');
+-        $question = new Question($question);
++        $question = new Question(self::sanitize($question));
+         $question->setHidden(true);
+ 
+         return $helper->ask($this->input, $this->getErrorOutput(), $question);
+@@ -303,7 +308,7 @@ class ConsoleIO extends BaseIO
+     {
+         /** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
+         $helper = $this->helperSet->get('question');
+-        $question = new ChoiceQuestion($question, $choices, $default);
++        $question = new ChoiceQuestion(self::sanitize($question), self::sanitize($choices), is_string($default) ? self::sanitize($default) : $default);
+         $question->setMaxAttempts($attempts ?: null); // IOInterface requires false, and Question requires null or int
+         $question->setErrorMessage($errorMessage);
+         $question->setMultiselect($multiselect);
+@@ -342,4 +347,35 @@ class ConsoleIO extends BaseIO
+ 
+         return $this->output;
+     }
++
++    /**
++     * Sanitize string to remove control characters
++     *
++     * If $allowNewlines is true, \x0A (\n) and \x0D\x0A (\r\n) are let through. Single \r are still sanitized away to prevent overwriting whole lines.
++     *
++     * All other control chars (except NULL bytes) as well as ANSI escape sequences are removed.
++     *
++     * @param string|iterable<string> $messages
++     * @return string|array<string>
++     * @phpstan-return ($messages is string ? string : array<string>)
++     */
++    public static function sanitize($messages, $allowNewlines = true)
++    {
++        // Match ANSI escape sequences:
++        // - CSI (Control Sequence Introducer): ESC [ params intermediate final
++        // - OSC (Operating System Command): ESC ] ... ESC \ or BEL
++        // - Other ESC sequences: ESC followed by any character
++        $escapePattern = '\x1B\[[\x30-\x3F]*[\x20-\x2F]*[\x40-\x7E]|\x1B\].*?(?:\x1B\\\\|\x07)|\x1B.';
++        $pattern = $allowNewlines ? "{{$escapePattern}|[\x01-\x09\x0B\x0C\x0E-\x1A]|\r(?!\n)}u" : "{{$escapePattern}|[\x01-\x1A]}u";
++        if (is_string($messages)) {
++            return Preg::replace($pattern, '', $messages);
++        }
++
++        $sanitized = array();
++        foreach ($messages as $key => $message) {
++            $sanitized[$key] = Preg::replace($pattern, '', $message);
++        }
++
++        return $sanitized;
++    }
+ }
diff -Nru composer-2.5.5/debian/patches/series composer-2.5.5/debian/patches/series
--- composer-2.5.5/debian/patches/series	2024-06-14 08:01:19.000000000 +0200
+++ composer-2.5.5/debian/patches/series	2025-12-30 17:00:22.000000000 +0100
@@ -15,3 +15,4 @@
 0015-Merge-pull-request-from-GHSA-v9qv-c7wm-wgmf.patch
 0016-Merge-pull-request-from-GHSA-47f6-5gq3-vx9c.patch
 0017-Fix-test.patch
+0018-Merge-commit-from-fork.patch

Attachment: signature.asc
Description: PGP signature

Reply via email to