CVE-2022-25866 (Other, published 2022-04-25T17:15Z)
Description: value: The package czproject/git-php before 4.0.3 are vulnerable to Command Injection via git argument injection. When calling the isRemoteUrlReadable($url, array $refs = NULL) function, both the url and refs parameters are passed to the git ls-remote subcommand in a way that additional flags can be set. The additional flags can be used to perform a command injection.
Severity: HIGH (CVSS v3 base score: 9.8)
Weakness: CWE-88 \u2014 Improper Neutralization of Argument Delimiters in a Command ('Argument Injection')
The product constructs a string for a command to be executed by a separate component
in another control sphere, but it does not properly delimit the
intended arguments, options, or switches within that command string.
Repository: https://github.com/czproject/git-php
Files changed:
src/Git.php
src/GitRepository.php
tests/GitPhp/GitRepository.branches.phpt
tests/GitPhp/GitRepository.files.phpt
tests/GitPhp/GitRepository.remotes.phpt
tests/GitPhp/GitRepository.tags.phpt
Commit message: Uses --end-of-options after command options (for security reasons)


Vulnerable code:
			$this->run('tag', $options, $name);
			$this->run('tag', $newName, $oldName);
			$this->run('merge', $options, $branch);
			$this->run('branch', $name);
			$this->run('checkout', $name);
				$this->run('rm', $item, '-r');
				$this->run('add', $item);
				$this->run('mv', $from, $to);
			$this->run('pull', $remote, $params);
			$this->run('push', $remote, $params);
			$this->run('fetch', $remote, $params);
			$this->run('remote', 'add', $params, $name, $url);
			$this->run('remote', 'rename', $oldName, $newName);
			$this->run('remote', 'remove', $name);
			$this->run('remote', 'set-url', $params, $name, $url);
$runner->assert(['branch', 'master']);
$runner->assert(['branch', 'develop']);
$runner->assert(['checkout', 'develop']);
$runner->assert(['merge', 'feature-1']);
$runner->assert(['checkout', 'master']);
	$runner->assert(['add', 'file1.txt']);
	$runner->assert(['add', 'file2.txt']);
	$runner->assert(['add', 'file3.txt']);
	$runner->assert(['add', 'file4.txt']);
	$runner->assert(['add', 'file5.txt']);
	$runner->assert(['rm', 'file1.txt', '-r']);
	$runner->assert(['rm', 'file2.txt', '-r']);
	$runner->assert(['rm', 'file3.txt', '-r']);
	$runner->assert(['rm', 'file4.txt', '-r']);
	$runner->assert(['rm', 'file5.txt', '-r']);
	$runner->assert(['mv', 'file1.txt', 'new1.txt']);
	$runner->assert(['mv', 'file2.txt', 'new2.txt']);
	$runner->assert(['mv', 'file3.txt', 'new3.txt']);
$runner->assert(['clone', '-q', 'git@github.com:czproject/git-php.git', __DIR__]);
$runner->assert(['remote', 'add', 'origin2', 'git@github.com:czproject/git-php.git']);
$runner->assert(['remote', 'add', 'remote', 'git@github.com:czproject/git-php.git']);
], 'only-push', 'test-url']);
$runner->assert(['remote', 'rename', 'remote', 'origin3']);
], 'origin3', 'test-url']);
$runner->assert(['remote', 'remove', 'origin2']);
$runner->assert(['push', 'origin']);
$runner->assert(['fetch', 'origin']);
$runner->assert(['pull', 'origin']);
$runner->assert(['tag', 'v1.0.0']);
$runner->assert(['tag', 'v2.0.0', 'v1.0.0']);

Fixed code:
					'--end-of-options',
					'--end-of-options',
				'--end-of-options',
			$this->run('tag', $options, '--end-of-options', $name);
			$this->run('tag', '--end-of-options', $newName, $oldName);
			$this->run('merge', $options, '--end-of-options', $branch);
			$this->run('branch', '--end-of-options', $name);
			$this->run('checkout', '--end-of-options', $name);
				$this->run('rm', '-r', '--end-of-options', $item);
				$this->run('add', '--end-of-options', $item);
				$this->run('mv', '--end-of-options', $from, $to);
			$this->run('pull', $params, '--end-of-options', $remote);
			$this->run('push', $params, '--end-of-options', $remote);
			$this->run('fetch', $params, '--end-of-options', $remote);
			$this->run('remote', 'add', $params, '--end-of-options', $name, $url);
			$this->run('remote', 'rename', '--end-of-options', $oldName, $newName);
			$this->run('remote', 'remove', '--end-of-options', $name);
			$this->run('remote', 'set-url', $params, '--end-of-options', $name, $url);
$runner->assert(['branch', '--end-of-options', 'master']);
$runner->assert(['branch', '--end-of-options', 'develop']);
$runner->assert(['checkout', '--end-of-options', 'develop']);
$runner->assert(['merge', '--end-of-options', 'feature-1']);
$runner->assert(['checkout', '--end-of-options', 'master']);
	$runner->assert(['add', '--end-of-options', 'file1.txt']);
	$runner->assert(['add', '--end-of-options', 'file2.txt']);
	$runner->assert(['add', '--end-of-options', 'file3.txt']);
	$runner->assert(['add', '--end-of-options', 'file4.txt']);
	$runner->assert(['add', '--end-of-options', 'file5.txt']);
	$runner->assert(['rm', '-r', '--end-of-options', 'file1.txt']);
	$runner->assert(['rm', '-r', '--end-of-options', 'file2.txt']);
	$runner->assert(['rm', '-r', '--end-of-options', 'file3.txt']);
	$runner->assert(['rm', '-r', '--end-of-options', 'file4.txt']);
	$runner->assert(['rm', '-r', '--end-of-options', 'file5.txt']);
	$runner->assert(['mv', '--end-of-options', 'file1.txt', 'new1.txt']);
	$runner->assert(['mv', '--end-of-options', 'file2.txt', 'new2.txt']);
	$runner->assert(['mv', '--end-of-options', 'file3.txt', 'new3.txt']);
$runner->assert(['clone', '-q', '--end-of-options', 'git@github.com:czproject/git-php.git', __DIR__]);
$runner->assert(['remote', 'add', '--end-of-options', 'origin2', 'git@github.com:czproject/git-php.git']);
$runner->assert(['remote', 'add', '--end-of-options', 'remote', 'git@github.com:czproject/git-php.git']);
], '--end-of-options', 'only-push', 'test-url']);
$runner->assert(['remote', 'rename', '--end-of-options', 'remote', 'origin3']);
], '--end-of-options', 'origin3', 'test-url']);
$runner->assert(['remote', 'remove', '--end-of-options', 'origin2']);
$runner->assert(['push', '--end-of-options', 'origin']);
$runner->assert(['fetch', '--end-of-options', 'origin']);
$runner->assert(['pull', '--end-of-options', 'origin']);
$runner->assert(['tag', '--end-of-options', 'v1.0.0']);
$runner->assert(['tag', '--end-of-options', 'v2.0.0', 'v1.0.0']);