Skip to content

SQL injection in ext-pgsql via E'...' backslash breakout

High
iluuu1994 published GHSA-7qpv-r5mr-78m4 Jul 30, 2026

Package

ext-pgsql (PHP)

Affected versions

<8.2.33
<8.3.33
<8.4.24
<8.5.9

Patched versions

8.2.33
8.3.33
8.4.24
8.5.9

Description

php_pgsql_convert() is used to convert and escape user-provided parameters in pg_insert(), pg_update(), pg_select(), and pg_delete(). It does so using PQescapeStringConn() and then wraps the result in an escape string constant, E'...' (via php_pgsql_add_quotes()).

php-src/ext/pgsql/pgsql.c

Lines 4751 to 4757 in cbc0489

ZSTR_LEN(str) = PQescapeStringConn(pg_link, ZSTR_VAL(str),
Z_STRVAL_P(val), Z_STRLEN_P(val), &escape_err);
if (escape_err) {
err = 1;
} else {
ZVAL_STR(&new_val, php_pgsql_add_quotes(str));
}

With standard_conforming_strings = on (the default since PostgreSQL 9.1), PQescapeStringConn() does not correctly escape values for the escape string constant E'...', as it does not escape \ under this configuration. When PQescapeStringConn() escapes ' as '', an attacker can trivially terminate the string by escaping the first single quote.

$result = pg_select($db, 'user', ['name' => "zzz\\' OR 1=1 --"]);
// SELECT * FROM "user" WHERE "name"='zzz\'' OR 1=1 --';
var_dump($result); // returned all rows

Note that the doubled \\ is a PHP escape sequence and that the \ appears only once in the parameter. Also note that pg_select() escapes the ' by doubling it but does not escape the \. Consequently, the first of the two ' characters is escaped (meaning that it represents a literal '), while the second terminates the string. Everything after that is interpreted as part of the query.

The solution changes php_pgsql_convert() to wrap parameters in non-escaping string constants instead.

Severity

High

CVE ID

CVE-2026-17543

Weaknesses

Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')

The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component. Without sufficient removal or quoting of SQL syntax in user-controllable inputs, the generated SQL query can cause those inputs to be interpreted as SQL instead of ordinary user data. Learn more on MITRE.

Credits