CVE-2024-35242 (published 2024-06-10T22:15Z)

Composer is a dependency manager for PHP. On the 2.x branch prior to versions 2.2.24 and 2.7.7, the `composer install` command running inside a git/hg repository which has specially crafted branch names can lead to command injection. This requires cloning untrusted repositories. Patches are available in version 2.2.24 for 2.2 LTS or 2.7.7 for mainline. As a workaround, avoid cloning potentially compromised repositories.\n


Weakness information:
cwe_id: NVD-CWE-noinfo
cwe_name: Insufficient Information
description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/composer/composer
commit_details: repo_url: https://github.com/composer/composer
author: Jordi Boggiano
author_date: 2024-06-10 14:56:13+02:00
msg: Merge pull request from GHSA-v9qv-c7wm-wgmf
repository: repo_url: https://github.com/composer/composer
repo_name: composer/composer
description: Dependency Manager for PHP
repo_language: PHP
owner: composer
file_changes: filename: VersionGuesser.php
change_type: ModificationType.MODIFY
diff: @@ -173,7 +173,7 @@ private function guessGitVersion(array $packageConfig, string $path): array
                 $featurePrettyVersion = $prettyVersion;
 
                 // try to find the best (nearest) version branch to assume this feature's version
-                $result = $this->guessFeatureVersion($packageConfig, $version, $branches, 'git rev-list %candidate%..%branch%', $path);
+                $result = $this->guessFeatureVersion($packageConfig, $version, $branches, ['git', 'rev-list', '%candidate%..%branch%'], $path);
                 $version = $result['version'];
                 $prettyVersion = $result['pretty_version'];
             }
@@ -248,7 +248,7 @@ private function guessHgVersion(array $packageConfig, string $path): ?array
             $branches = array_map('strval', array_keys($driver->getBranches()));
 
             // try to find the best (nearest) version branch to assume this feature's version
-            $result = $this->guessFeatureVersion($packageConfig, $version, $branches, 'hg log -r "not ancestors(\'%candidate%\') and ancestors(\'%branch%\')" --template "{node}\\n"', $path);
+            $result = $this->guessFeatureVersion($packageConfig, $version, $branches, ['hg', 'log', '-r', 'not ancestors(\'%candidate%\') and ancestors(\'%branch%\')', '--template', '"{node}\\n"'], $path);
             $result['commit'] = '';
             $result['feature_version'] = $version;
             $result['feature_pretty_version'] = $version;
@@ -261,13 +261,12 @@ private function guessHgVersion(array $packageConfig, string $path): ?array
 
     /**
      * @param array<string, mixed>     $packageConfig
-     * @param string[]                 $branches
-     *
-     * @phpstan-param non-empty-string $scmCmdline
+     * @param list<string>             $branches
+     * @param list<string>             $scmCmdline
      *
      * @return array{version: string|null, pretty_version: string|null}
      */
-    private function guessFeatureVersion(array $packageConfig, ?string $version, array $branches, string $scmCmdline, string $path): array
+    private function guessFeatureVersion(array $packageConfig, ?string $version, array $branches, array $scmCmdline, string $path): array
     {
         $prettyVersion = $version;
 
@@ -309,7 +308,9 @@ private function guessFeatureVersion(array $packageConfig, ?string $version, arr
                         continue;
                     }
 
-                    $cmdLine = str_replace(['%candidate%', '%branch%'], [$candidate, $branch], $scmCmdline);
+                    $cmdLine = array_map(static function (string $component) use ($candidate, $branch) {
+                        return str_replace(['%candidate%', '%branch%'], [$candidate, $branch], $component);
+                    }, $scmCmdline);
                     $promises[] = $this->process->executeAsync($cmdLine, $path)->then(function (Process $process) use (&$length, &$version, &$prettyVersion, $candidateVersion, &$promises): void {
                         if (!$process->isSuccessful()) {
                             return;

programming_language: PHP
filename: VersionGuesserTest.php
change_type: ModificationType.MODIFY
diff: @@ -117,7 +117,7 @@ public function testGuessVersionReadsAndRespectsNonFeatureBranchesConfigurationF
                 'stdout' => "  arbitrary $commitHash Commit message\n* feature $anotherCommitHash Another message\n",
             ],
             [
-                'cmd' => 'git rev-list arbitrary..feature',
+                'cmd' => ['git', 'rev-list', 'arbitrary..feature'],
                 'stdout' => "$anotherCommitHash\n",
             ],
         ], true);
@@ -147,7 +147,7 @@ public function testGuessVersionReadsAndRespectsNonFeatureBranchesConfigurationF
                 'stdout' => "  latest-testing $commitHash Commit message\n* feature $anotherCommitHash Another message\n",
             ],
             [
-                'cmd' => 'git rev-list latest-testing..feature',
+                'cmd' => ['git', 'rev-list', 'latest-testing..feature'],
                 'stdout' => "$anotherCommitHash\n",
             ],
         ], true);
@@ -352,7 +352,7 @@ public function testRemoteBranchesAreSelected(): void
                         "remotes/origin/1.5 03a15d220da53c52eddd5f32ffca64a7b3801bea Commit message\n",
             ],
             [
-                'cmd' => 'git rev-list remotes/origin/1.5..feature-branch',
+                'cmd' => ['git', 'rev-list', 'remotes/origin/1.5..feature-branch'],
                 'stdout' => "\n",
             ],
         ], true);

programming_language: PHP