
GitList is a modern Git repository viewer.
In GitList versions 0.6.0 and below, there is a vulnerability that passes improperly validated input to system functions, allowing arbitrary commands to be executed with PHP user privileges.
Run the following command to start the GitList server 0.6.0.
docker compose up -d
Install dependencies before running poc.py.
pip install requests
Once the environment is set up, access http://127.0.0.1:8080 and verify that a test repository named example exists.
GitList uses git grep to search code within repositories.
public function searchTree($query, $branch)
{
if (empty($query)) {
return null;
}
$query = escapeshellarg($query);
try {
$results = $this->getClient()->run($this, "grep -i --line-number {$query} $branch");
} catch (\RuntimeException $e) {
return false;
}
Here, $query is the search keyword, and $branch is the target branch for the search.
If an attacker passes --open-files-in-pager=id; as the search term, the id command will be executed on the system.
This vulnerability occurs for two reasons:
escapeshellarg() functionTheoretically, after passing through $query = escapeshellarg($query);, the input becomes a string wrapped in single quotes. However, escapeshellarg() prevents injection from the shell's perspective, but it does not prevent git's own option parser from interpreting strings starting with -- as options.
--open-files-in-pager optionThis option of git grep designates an external pager program to display search results, and it has the characteristic of directly executing the passed value as a system command.
[repo_name]/tree/[keyword]/search) contains two arguments: [repo_name] and [keyword].[repo_name] must be a repository existing in GitList, and [keyword] must be a search keyword that produces at least one search result.
(In this reproduction, example was used as the repository and a as the keyword.)Run poc.py using the following command.
This script executes touch /tmp/success_dddo0, creating an empty file named success_dddo0 in the /tmp directory of the server.
python3 poc.py http://127.0.0.1:8080
After the request is sent, verify that success_dddo0 was successfully created using the following command.
docker compose exec web ls -l /tmp/success_dddo0
After running the PoC, it can be confirmed that an arbitrary system command (touch /tmp/success_dddo0) was successfully executed inside the server, creating the file.

docker compose down
You should update GitList to the latest version.
Code fix:
public function searchTree($query, $branch)
{
if (empty($query)) {
return null;
}
$query = preg_replace('/(--?[A-Za-z0-9\-]+)/', '', $query);
$query = escapeshellarg($query);
try {
$results = $this->getClient()->run($this, "grep -i --line-number -- {$query} $branch");
} catch (\RuntimeException $e) {
return false;
}
GitList fixed this vulnerability by using a regular expression to remove illegal - prefixes from the search term ($query) and by adding -- (the option terminator identifier) to the git grep command, forcing all subsequent input to be treated only as normal strings (search terms) rather than command options.