CVE-2025-1094 - Exploiting SQL Injection in PostgreSQL libpq Escape Functions
PostgreSQL is famous for being a secure and reliable open-source database. But recently, a vulnerability surfaced, affecting the libpq client library and several PostgreSQL command-line utilities. Tracked as CVE-2025-1094, this vulnerability demonstrates how classic mistakes with quoting and character encodings can slip even into trusted projects.
This article breaks down the CVE for developers, pen-testers, and anyone curious about database security—using simple American English, original references, code snippets, and real exploit details.
What is CVE-2025-1094?
CVE-2025-1094 is an improper neutralization of quoting syntax (CWE-89: SQL Injection) in PostgreSQL's connection library functions:
PQescapeStringConn()
These functions are supposed to sanitize user input—preventing attackers from hijacking SQL queries. But due to incorrect handling of character encodings (mostly if using the BIG5 client encoding with an EUC_TW or MULE_INTERNAL server encoding), it’s possible for an attacker to inject SQL.
Your app or scripts allow untrusted input to land on the PostgreSQL command line.
Affected versions are PostgreSQL before 17.3, 16.7, 15.11, 14.16, and 13.19.
Original References
- PostgreSQL Official Security Release
- CVE Details Listing
- Knowledge base entry
How Does the Exploit Work?
The vulnerability stems from how certain escape functions fail to neutralize special characters when mixing specific client and server encodings—namely BIG5 on the client and EUC_TW or MULE_INTERNAL on the server. These functions are expected to "quote" dangerous characters so that a literal value can't break out of what's quoted in SQL, or that a user-chosen identifier can't become "malicious" SQL.
But with these encodings, some characters can "slip through" the checks.
Example Exploit
Let’s sketch out what this could look like in practice.
Suppose your application accepts user input and tries to sanitize it like this
char escapedInput[2048];
const char *origInput = argv[1]; // Input from user
PGconn *conn = PQconnectdb("..."); // Assume connected
// Attempt to safely quote input (client_encoding is BIG5)
PQescapeStringConn(conn, escapedInput, origInput, strlen(origInput), NULL);
// Now construct a SQL command for psql or send to psql process
char sql_cmd[4096];
snprintf(sql_cmd, 4096, "SELECT * FROM users WHERE name = '%s';", escapedInput);
// System call or piping to psql -- DANGEROUS!
system(sql_cmd); // or: popen("psql -c \"" ... )
Expected: The user can't break out of the quotes.
Actual: If origInput is crafted in BIG5 encoding, and server is EUC_TW, special sequences could trick the server into seeing '; DROP TABLE users; -- outside the original quotes, resulting in SQL injection.
Step 2: Attacker's Input
Suppose the attacker provides input such that, when encoded in BIG5, the resulting byte sequence contains a valid single quote character x27 in a multibyte sequence not properly escaped due to encoding confusion:
abc\xA3\x7F'; DROP TABLE users; --
When the server (expecting EUC_TW) sees this, it can "misread" the encoding boundary. The pseudo-escaped character becomes an actual SQL break-out.
The intended SQL
SELECT * FROM users WHERE name = 'abc…';
becomes
SELECT * FROM users WHERE name = 'abc'; DROP TABLE users; --';
Server-side apps using psql or constructing SQL queries in C are most at risk.
- *Common web frameworks* (like Python's psycopg, Node's pg, etc.) are safe by default—unless you drop down to these escape functions yourself.
How To Fix
- Upgrade immediately: If you use any version below 17.3, 16.7, 15.11, 14.16, or 13.19, apply security patches.
- Don't use escape functions to build command-line SQL: Instead, prefer query parameterization. For example:
PGresult *res = PQexecParams(conn,
"SELECT * FROM users WHERE name=$1",
1, NULL,
&userInput,
NULL, NULL, );
- Review your encoding settings if you support internationalization—especially for TW, BIG5, MULE_INTERNAL users.
Final Notes
This bug is a lesson on why parameterized queries and defense-in-depth matter. Stay updated and don’t rely on escaping and quoting functions to keep your SQL safe, especially when character encodings can mix.
For further reading, check the official security advisory and the PostgreSQL wiki.
Timeline
Published on: 02/13/2025 13:15:09 UTC
Last modified on: 02/13/2025 22:15:11 UTC