NULL Pointer Dereference in PDO quoting

Inhalt

Product: PHP Version: 8.5.0-DEV (CLI) CWE-ID: CWE-476: NULL Pointer Dereference CVSS vector v.4.0: 8.2 (AV:N/AC:H/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N) Description: A NULL pointer dereference occurs when the application dereferences a pointer that it expects to be valid, but is NULL, typically causing a crash or exit. Exploitation conditions: An unauthorized user Mitigation: Explicitly check whether a NULL pointer exists before dereferencing it. Researcher: Aleksey Solovev (Positive Technologies)

Research

The vulnerable source code is the ZSTR_LEN(plc->quoted) macro call in the pdo_parse_params function in php-src/ext/pdo/pdo_sql_parser.re. Inside the ZSTR_LEN(plc->quoted) macro, the len field is accessed.

Figure 1. The ZSTR_LEN macro However, when using a special character sequence, plc->quoted is equal to 0x0.

Figure 2. The vulnerable source code The plc->quoted field is generated in this case on line 302 when calling the stmt->dbh->methods->quoter function.

Figure 3. plc->quoted initialization When calling stmt->dbh->methods->quoter, the quoting function pgsql_handle_quoter for PG will be called. On line 407, it will call the PG library function PQescapeStringConn, which will return an error when processing the special sequence, returning NULL as a result. This result will be assigned to the plc->quoted field.

Figure 4. Returning NULL when error occurs ## Vulnerability reproduction

The PHP language was compiled using the following commands.

Listing 1. Compiling PHP

$ git clone https://github.com/php/php-src.git
$ cd php-src
$ ./buildconf
$ ./configure CFLAGS="-fsanitize=address -g" CXXFLAGS="-fsanitize=address -g" 
LDFLAGS="-fsanitize=address" --with-pdo-pgsql --enable-debug
$ make -j8
$ ./sapi/cli/php -v
PHP 8.5.0-dev (cli) (built: Sep 22 2025 13:24:35) (NTS DEBUG)
Copyright (c) The PHP Group
Zend Engine v4.5.0-dev, Copyright (c) Zend Technologies
    with Zend OPcache v8.5.0-dev, Copyright (c), by Zend Technologies

Next, the following PHP code was placed on the server, causing to Segmentation fault. Enabling the PDO::ATTR_EMULATE_PREPARES mode is the key element of this code. The problem is caused by a non-existent sequence of characters in hexadecimal notation, for example \x99.

Listing 2. Source code on the server

        ]);

        $sql = "SELECT * FROM users where username = :username";
        $stmt = $pdo->prepare($sql);
        
        $p1 = "alice\x99";
        $stmt->execute(['username' => $p1]);

        foreach ($stmt as $row) {
            print_r($row);
        }
    } catch (PDOException $e) { echo $e->getMessage(); }
?>

Executing the following PHP code results in Segmentation fault, which leads to Denial of Service (DoS).

Figure 5. Demonstration of the vulnerability ## Security impact

If there is no extra validaiton for zero byte of the quoted user input, then it could lead to a potential DoS and for ZTS mode stopping all other currently served requests in the process.

Credits

Aleksey Solovev (Positive Technologies)

Verknuepfte CVEs

CVE-ID Severity (CVE.org) CVSS (CVE.org) EPSS EPSS-% Veroeffentlicht (CVE.org)

CVE-2025-14180

- - - -

Quellen-Details

Bezeichnung Name Kategorie Tags Zielgruppe Sprache Feed-URL
PHP Security (php/php-src GHSA)

php_sec

vendor_advisory php, runtime - de https://github.com/php/php-src/security/advisories