A recent vulnerability, CVE-2024-1597, affects the PostgreSQL JDBC Driver, also known as pgjdbc. This flaw allows attackers to perform SQL injection attacks if the driver is configured to use PreferQueryMode=SIMPLE. If you are using the default settings, you are not at risk. However, if you explicitly set your JDBC url to PreferQueryMode=SIMPLE, you could be vulnerable—especially if user inputs are not tightly controlled and are used as parameters in queries.
Versions before 42.7.2, 42.6.1, 42.5.5, 42.4.4, 42.3.9, 42.2.8 are vulnerable
- Exploitable when a numeric placeholder is directly after a minus (-) and immediately followed by a string placeholder on the same line
How Does the Attack Work?
The attack relies on a quirk in how the pgjdbc driver processes SQL queries in PreferQueryMode=SIMPLE. This mode doesn't parse or rewrite queries on the client—it simply sends the textual query to PostgreSQL. Thus, it can't distinguish between user inputs and SQL code when certain placeholders are used.
The Vulnerable Pattern
String sql = "SELECT * FROM accounts WHERE balance = -? AND username = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, amount);
ps.setString(2, userInput);
What’s wrong here?
- There is a -? where the ? is for a numeric value (like an integer or float), _immediately preceded by a minus sign_.
On the same line, another parameter (in this case, a string for username) is used.
In default (extended query) mode, the driver prevents SQL injection via parameterization. However, in SIMPLE mode, the splitting for parameter values can be defective in this pattern, letting attackers smuggle SQL code in their "string" input.
Suppose the attacker controls userInput. They could pass the following string
' OR 1=1; --
When plugged into the query, the server would see
SELECT * FROM accounts WHERE balance = -<amount> AND username = '' OR 1=1; --'
Meaning, the OR 1=1 clause is injected, potentially exposing all accounts.
Vulnerable Java code
// Vulnerable ONLY if using PreferQueryMode=SIMPLE
String sql = "SELECT * FROM accounts WHERE amount = -? AND user_id = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, amount);
ps.setString(2, userInput); // Controlled by attacker!
Malicious user input
' UNION SELECT * FROM secrets; --
Resulting SQL sent to PostgreSQL (after substitution)
SELECT * FROM accounts WHERE amount = -123 AND user_id = '' UNION SELECT * FROM secrets; --'
This results in exposing data from a table named secrets.
You run a driver version LESS than 42.7.2, 42.6.1, 42.5.5, 42.4.4, 42.3.9, or 42.2.8
- Your queries include user-supplied parameters in the vulnerable pattern (-? for numbers immediately followed by ? for string, same line)
Links and References
- CVE-2024-1597 Official CVE Entry
- pgjdbc Security Advisories
- pgjdbc Release Notes
- PostgreSQL JDBC Driver Docs
Summary Table
| Vulnerable? | PreferQueryMode | Driver Version | Dangerous Query? |
|-------------|-----------------|--------------------|----------------------|
| ✔️ | SIMPLE | < 42.7.2 | Yes |
| ❌ | EXTENDED (default)| Any supported ver | No |
| ❌ | SIMPLE | 42.7.2 or newer | (fixed) |
Final Thoughts
CVE-2024-1597 is a reminder that even when using parameterized queries, the driver mode and usage patterns matter. Most users are safe _by default_. But if you need to use non-default query modes or have legacy code, audit your JDBC usage and upgrade your drivers ASAP.
Stay safe—patch fast, audit often!
*This post is original, crafted exclusively for clear understanding of the issue. For further details, always consult the official references and test your own codebase thoroughly.*
Timeline
Published on: 02/19/2024 13:15:07 UTC
Last modified on: 03/25/2024 16:42:20 UTC