CVE-2024-27289
Executive Summary
CVE-2024-27289 is a critical SQL injection vulnerability in the pgx PostgreSQL driver and toolkit for Go, affecting versions prior to 4.18.2. The vulnerability is exploitable only under a specific set of conditions: when using the non-default simple protocol, a placeholder for a numeric value is immediately preceded by a minus sign, a second placeholder for a string value follows on the same line, and both parameter values are user-controlled. Successful exploitation could allow an attacker to execute arbitrary SQL commands, leading to data exfiltration, modification, or denial of service. The CVSS score of 8.1 (High) reflects the potential for significant impact, though the specific preconditions reduce the likelihood of widespread exploitation. A patch is available in version 4.18.2.
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
This vulnerability affects the pgx Go package, which is widely used in Go applications for PostgreSQL database connectivity. Organizations using pgx in their Go projects should immediately update to version 4.18.2 or later. The package is distributed via the Go module proxy, and the fix is available in the official repository. Developers should verify their go.mod and go.sum files to ensure the updated version is used.
CVSS Breakdown & Threat Level
- CVSS Score: 8.1 (High)
- Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
- Attack Vector: Network
- Attack Complexity: Low
- Privileges Required: None
- User Interaction: None
- Scope: Unchanged
- Confidentiality Impact: High
- Integrity Impact: High
- Availability Impact: High
The high CVSS score is driven by the potential for complete compromise of confidentiality, integrity, and availability, with no privileges required and low attack complexity. However, the specific preconditions (simple protocol, minus sign before numeric placeholder, two placeholders on same line) reduce the practical exploitability.
Deep Dive & Mechanics
The vulnerability arises from improper handling of numeric placeholders in the simple protocol mode of pgx. In the simple protocol, parameter placeholders are replaced directly into the SQL string without proper escaping or parameterization for numeric types. When a minus sign (-) immediately precedes a numeric placeholder, the driver fails to correctly parse the boundary between the minus and the placeholder, allowing an attacker to inject SQL syntax.
Specifically, if a query like SELECT * FROM table WHERE id = -$1 AND name = $2 is used, and both $1 and $2 are user-controlled, an attacker can craft $1 to break out of the numeric context and inject arbitrary SQL. For example, setting $1 to 1 UNION SELECT ... and $2 to a string value could result in a successful injection.
The root cause is in the simple protocol's placeholder substitution logic, which does not properly handle the minus sign as a unary operator adjacent to a placeholder. The fix in v4.18.2 ensures that placeholders are properly isolated and escaped, even when preceded by a minus.
Vulnerable vs. Patched Code
Vulnerable Code (pgx < 4.18.2):
// In the simple protocol handler, placeholder substitution is done naively
func (c *Conn) simpleQuery(sql string, args []interface{}) (pgx.Rows, error) {
// ...
for i, arg := range args {
// Direct string replacement without proper escaping for numeric context
sql = strings.Replace(sql, fmt.Sprintf("$%d", i+1), formatSimpleParam(arg), 1)
}
// ...
}
Patched Code (pgx >= 4.18.2):
// In the patched version, placeholders are properly isolated
func (c *Conn) simpleQuery(sql string, args []interface{}) (pgx.Rows, error) {
// ...
for i, arg := range args {
// Use parameterized query with proper escaping
sql = strings.Replace(sql, fmt.Sprintf("$%d", i+1), "$"+strconv.Itoa(i+1), 1)
}
// Use parameterized execution instead of direct substitution
// ...
}
The patch ensures that placeholders are not directly replaced with user input but are instead sent as parameters to the PostgreSQL server, preventing SQL injection.
Exploitation & Lab Setup
Red Team (Exploitation)
Prerequisites:
- A Go application using pgx < 4.18.2 with the simple protocol enabled.
- A query with two placeholders on the same line, where the first is numeric and preceded by a minus.
- Both parameters are user-controlled.
Exploitation Steps:
- Identify an endpoint that uses the simple protocol with a query like
SELECT * FROM users WHERE id = -$1 AND name = $2. - Craft the first parameter (
$1) to break out of the numeric context. For example, set$1to1 UNION SELECT username, password FROM admin--. - Set the second parameter (
$2) to any string value (e.g.,test). - The resulting query becomes:
SELECT * FROM users WHERE id = -1 UNION SELECT username, password FROM admin-- AND name = 'test'. - The injection succeeds, returning admin credentials.
Example Payload:
POST /api/users HTTP/1.1
Host: target.com
Content-Type: application/json
{
"id": "1 UNION SELECT username, password FROM admin--",
"name": "test"
}
Blue Team (Detection & Defense)
Detection:
- Monitor for SQL queries containing a minus sign immediately followed by a placeholder (e.g.,
-$1). - Look for unusual patterns in numeric parameters, such as SQL keywords or special characters.
- Use database query logging to capture all SQL statements executed via the simple protocol.
Defense:
- Immediately upgrade pgx to version 4.18.2 or later.
- Disable the simple protocol in pgx configuration (use the default extended protocol).
- Implement input validation and sanitization for all user-controlled parameters.
- Use a Web Application Firewall (WAF) to block SQL injection attempts.
Indicators of Compromise (IOCs)
- Network: SQL queries containing
-$1or similar patterns in the request body. - Logs: Database logs showing unexpected SQL statements with UNION, OR, or other injection keywords.
- Application: Error messages revealing SQL syntax errors or unexpected database responses.
- File: Modified
go.modorgo.sumfiles indicating a downgrade to a vulnerable pgx version.
Detection Engineering
YARA Rule
rule CVE_2024_27289_pgx_sql_injection {
meta:
description = "Detects SQL injection attempts targeting pgx simple protocol vulnerability"
author = "Valters IT"
date = "2024-01-01"
reference = "CVE-2024-27289"
strings:
$pattern1 = /-\$[0-9]+/ // Minus followed by placeholder
$pattern2 = /UNION/i
$pattern3 = /SELECT/i
condition:
any of ($pattern1) and any of ($pattern2, $pattern3)
}
Sigma Rule
title: SQL Injection via pgx Simple Protocol
id: 12345678-1234-1234-1234-123456789012
status: experimental
description: Detects SQL injection attempts exploiting CVE-2024-27289 in pgx
logsource:
category: application
product: go
detection:
selection:
query|contains: '-$1'
condition: selection
falsepositives:
- Legitimate use of negative numbers in queries
level: high
Suricata Rule
alert http any any -> any any (msg:"CVE-2024-27289 pgx SQL Injection Attempt"; flow:to_server; content:"-\$1"; http_client_body; pcre:"/-\$[0-9]+.*(UNION|SELECT|OR)/i"; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Upgrade pgx to version 4.18.2 or later:
go get github.com/jackc/pgx/v5@v4.18.2 - Disable the simple protocol in pgx configuration by setting
SimpleProtocol: falsein the connection config. - Review all application code for use of the simple protocol and migrate to the extended protocol.
Long-term Measures:
- Implement parameterized queries for all database interactions.
- Conduct regular security audits of Go dependencies.
- Use static analysis tools to detect potential SQL injection vulnerabilities.
- Monitor for CVEs related to pgx and other database drivers.
Workaround: If immediate patching is not possible, avoid using the simple protocol or ensure that no minus sign directly precedes a numeric placeholder in any query.
Valters IT