CVEReports
Reports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Reports
  • Sitemap
  • RSS Feed

Company

  • About
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Powered by Google Gemini & CVE Feed

|
•

CVE-2025-58450
CVSS 9.3|EPSS 0.04%

pREST-o Change-o: Turning REST APIs into Remote Shells via CVE-2025-58450

Amit Schendel
Amit Schendel
Senior Security Researcher•January 2, 2026•6 min read
PoC Available

Executive Summary (TL;DR)

pREST, the tool that magically turns PostgreSQL databases into REST APIs, had a magical flaw: it trusted user input to build SQL structure. By manipulating parameters like `_join` and `_returning`, attackers could bypass validation and execute arbitrary SQL, leading to total database compromise. Fixed in version 2.0.0-rc3.

A systemic SQL injection vulnerability in pREST allows unauthenticated remote attackers to execute arbitrary SQL commands via manipulated API parameters. The flaw stems from widespread string concatenation in critical query builders like JOIN and RETURNING clauses.

The Hook: API Magic or Black Magic?

pREST (PostgreSQL REST) is one of those tools developers love. It promises to take your existing PostgreSQL database and, with a wave of a wand, expose it as a fully functional RESTful API. No boilerplate, no ORM headaches, just instant CRUD operations. It’s efficient, fast, and—until recently—dangerously trusting.

The core promise of pREST is that it handles the SQL generation for you. You send a GET request to /users, and it builds SELECT * FROM users. You add ?age=$gt:18, and it adds the WHERE clause. It’s a translation layer. But as any security researcher knows, translation layers are where the bodies are buried.

CVE-2025-58450 isn't just a simple 'oops' in a search bar. It is a systemic failure in how pREST constructed its SQL queries. The application was taking URL parameters intended to define query structure—like which tables to join or which columns to return—and pasting them directly into the SQL string. It’s the architectural equivalent of letting the user write their own police report.

The Flaw: Systemic String Concatenation

The root cause here is a classic that refuses to die: String Concatenation. In 2025, we should be using parameterized queries (prepared statements) for everything. But pREST sits in a unique position where it has to build dynamic queries based on dynamic URL parameters. While the values might have been parameterized in some places, the identifiers (table names, column names) and keywords (JOIN types) were not.

The vulnerability was identified in four critical areas:

  1. _returning: Used to define what data comes back after an INSERT/UPDATE. The code blindly trusted this list.
  2. _join: Used to link tables. The join type (INNER, LEFT) and the table identifiers were vulnerable.
  3. _groupby: Specifically the HAVING clause, which often handles aggregate filtering.
  4. Script Templates: Custom SQL templates that lacked proper parameterization mechanisms.

Because pREST acts as a direct interface to the DB, failing to sanitize these inputs means the attacker isn't just tricking a web app; they are speaking directly to the PostgreSQL engine with the privileges of the API user.

The Code: A Tale of Two Commits

Let's look at the "Smoking Gun" in the code. The patch, found in commit 47d02b87842900f77d76fc694d9aa7e983b0711c, reveals the extent of the negligence.

The Vulnerable Pattern (Conceptual) In the _join handler, the code was essentially doing this:

// Pseudocode representation of the flaw
sqlQuery += " " + joinType + " JOIN " + tableName + " ON " + ...

There was no check to see if joinType was actually a valid SQL keyword like INNER or LEFT. An attacker could theoretically pass LEFT JOIN users ON 1=1; DROP TABLE logs; -- as the join type, and the query builder would happily stitch it together.

The Fix: Regex and Whitelists The developers introduced a strict regex validator and a whitelist for join types. Here is the logic that saved the day:

// The new Sheriff in town: Regex Validation
var identRe = regexp.MustCompile(`^[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*$`)
 
// Whitelisting Join Types
validJoinTypes := map[string]bool{
    "INNER": true, "LEFT": true, "RIGHT": true,
    "FULL": true, "CROSS": true,
}
 
if !validJoinTypes[strings.ToUpper(joinType)] {
    return fmt.Errorf("invalid join type")
}
 
// Quoting Identifiers
formattedTable = fmt.Sprintf("\"%s\"", tableName)

They now force every table and column name to match a strict alphanumeric pattern AND wrap them in double quotes. This prevents the injector from breaking out of the identifier context.

The Exploit: Exfiltration via API

So, how do we weaponize this? We don't need a fancy exploit script; curl is enough. The goal is to manipulate the query structure to leak data we shouldn't see.

Scenario 1: The _returning Leak When you perform an operation that supports RETURNING (like an INSERT or sometimes a forced SELECT context), you can ask the DB to return specific columns. If this input is unsanitized, we can inject functions.

# Conceptual Exploit
GET /public/users?_returning=password,pg_read_file('/etc/passwd')

If the application blindly appends the query to RETURNING password, pg_read_file('/etc/passwd'), the API response might include the file contents alongside the user data.

Scenario 2: The _join Smash The _join parameter takes a complex syntax like table:field. If we manipulate the join type or the table identifier, we can alter the logic.

# Injecting into the Join Type (Pre-fix)
GET /public/products?_join=UNION SELECT usename, passwd FROM pg_shadow --:products.id:id

Because the code didn't validate that the join type was actually a "JOIN", we replace INNER with a UNION SELECT, effectively appending a second result set containing the database shadow file (hashes).

The Impact: Why This Scores a 9.3

A CVSS score of 9.3 is reserved for vulnerabilities that effectively mean "Game Over." This isn't an obscure race condition; it is a reliable, unauthenticated remote code execution (via SQL) vector.

1. Full Data Exfiltration: Attackers can dump the entire database. Since pREST is designed to expose data, it does half the work for them.

2. Lateral Movement: If the PostgreSQL instance has extensions enabled (like plpython or dblink), an attacker could escalate from SQL injection to Operating System Command Execution.

3. DoS: Trivial. ?_returning=pg_sleep(1000) on a public endpoint will exhaust the connection pool instantly.

[!NOTE] The severity is compounded by the fact that pREST is often deployed as a middleware layer, meaning it might be the only thing standing between the public internet and your core database.

The Fix: Stop the Bleeding

The remediation is straightforward but urgent. You must update pREST to version 2.0.0-rc3 or later immediately. The patch does not just "fix" the specific injection points; it changes the philosophy of how identifiers are handled by enforcing quoting and regex validation.

Mitigation Strategies if You Can't Patch:

  • WAF Rules: Block any request containing SQL keywords (UNION, SELECT, RETURNING, pg_) in the query string. This is brittle but better than nothing.
  • Least Privilege: Ensure the database user that pREST connects with has restricted permissions. It should not be a superuser. It should not have access to pg_shadow or file read functions.
  • Disable Features: If you don't use the _join or _returning features, consider using a reverse proxy (like Nginx) to strip those parameters from incoming requests before they reach pREST.

Official Patches

pRESTOfficial patch commit

Fix Analysis (1)

Technical Appendix

CVSS Score
9.3/ 10
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
EPSS Probability
0.04%
Top 100% most exploited

Affected Systems

pREST API ServerPostgreSQL Databases exposed via pREST

Affected Versions Detail

ProductAffected VersionsFixed Version
pREST
prestd
< 2.0.0-rc32.0.0-rc3
AttributeDetail
CWE IDCWE-89
Attack VectorNetwork
CVSS v4.09.3 (Critical)
EPSS Score0.0004 (Low Confidence)
ImpactCritical (Data Exfiltration, RCE via SQL)
Exploit StatusPoC Available / High Probability

MITRE ATT&CK Mapping

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1059.001Command and Scripting Interpreter: SQL
Execution
CWE-89
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')

Vulnerability Timeline

Vulnerability Timeline

Vulnerability identified and Patch Released
2025-01-02
CVE-2025-58450 Assigned
2025-01-02

References & Sources

  • [1]GHSA-p46v-f2x8-qp98 Advisory
  • [2]NVD Entry

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.