Get the latest, first
arrowBlog
CVE-2025-1094: SQL Injection Vulnerability in PostgreSQL’s Escaping Functions

CVE-2025-1094: SQL Injection Vulnerability in PostgreSQL’s Escaping Functions

Mar 10, 2025

Amit Schendel
Security Researcher

Introduction

CVE-2025-1094 presents a critical challenge to established SQL security paradigms, effectively circumventing fundamental best practices. Though initially reported over a month ago, the gravity of its implications warrants an extensive analysis. This vulnerability challenges the long-held assumption that proper escaping guarantees protection against SQL injection attacks. 

Affecting PostgreSQL’s core escaping functions and the psql interactive terminal, it exposes a critical flaw in the handling of invalid multibyte characters (e.g. UTF-8).

Executive Summary

CVE-2025-1094 is a high-severity SQL injection vulnerability affecting PostgreSQL’s escaping functions (PQescapeLiteral(), PQescapeIdentifier(), PQescapeString(), and PQescapeStringConn()) and the interactive terminal psql. This vulnerability arises due to improper neutralization of quoting syntax, which allows attackers to bypass escaping mechanisms under specific conditions. The issue is further exacerbated when certain multibyte character encodings (e.g., BIG5, EUC_TW, or MULE_INTERNAL) are used, enabling SQL injection attacks.

The vulnerability was discovered by Stephen Fewer, a Principal Security Researcher at Rapid7, during research into the exploitation of another vulnerability (CVE-2024-12356). This discovery highlights the interconnected nature of vulnerabilities and the importance of robust input validation. PostgreSQL versions prior to 17.3, 16.7, 15.11, 14.16, and 13.19 are affected. The vulnerability has a CVSS score of 8.1 (High), reflecting its potential impact on confidentiality, integrity, and availability.

Technical Details

Affected Components and Versions

The vulnerability affects the following PostgreSQL components:

  • Escaping functions in the libpq library:
    • PQescapeLiteral()
    • PQescapeIdentifier()
    • PQescapeString()
    • PQescapeStringConn()
  • Command-line utility programs, including psql.

Affected PostgreSQL versions:

  • PostgreSQL 13.x versions prior to 13.19
  • PostgreSQL 14.x versions prior to 14.16
  • PostgreSQL 15.x versions prior to 15.11
  • PostgreSQL 16.x versions prior to 16.7
  • PostgreSQL 17.x versions prior to 17.3

Vulnerability Description

The vulnerability stems from improper handling of invalidly encoded multibyte characters in escaping functions. Specifically:

  1. When invalid or incomplete multibyte characters are processed, they can bypass the escaping mechanisms.
  2. This allows attackers to inject malicious SQL commands into queries constructed using these escaping functions.
  3. In the psql interactive terminal, this can lead to arbitrary SQL injection or even arbitrary code execution (ACE) via meta-commands (e.g., ! for executing shell commands).

Example Scenario

An attacker could exploit this vulnerability by providing malicious input that includes invalid multibyte characters. For example:

  • The attacker crafts input that appears safe but includes invalid characters to bypass quoting.
  • The application passes this input to psql for execution.
  • The malicious input is interpreted as part of the SQL query, allowing the attacker to execute arbitrary SQL or shell commands.

Root Cause Analysis

The root cause lies in the improper handling of invalid multibyte characters in the escaping functions. These functions fail to:

  1. Properly validate multibyte character sequences.
  2. Ensure that invalid characters cannot escape the quoting mechanism.

Code Example of the Vulnerability

The following snippet illustrates the problematic behavior in the PQescapeStringInternal() function:

while (remaining > 0 && *source != '\0') {
    char c = *source;
    int charlen = pg_encoding_mblen(encoding, source);

    if (remaining < charlen) {
        // Incomplete multi-byte character
        if (error)
            *error = 1;
        if (conn)
            libpq_append_conn_error(conn, "incomplete multibyte character");
        break;
    }

    // Process character (incorrectly handles invalid sequences)
    for (int i = 0; i < charlen; i++) {
        *target++ = *source++;
        remaining--;
    }
}

Here, the function fails to properly validate multi-byte characters, allowing invalid sequences to bypass escaping mechanisms.

Patch Analysis

The PostgreSQL development team addressed CVE-2025-1094 in commit 5dc1e42b4fa6a4434afa7d7cdcf0291351a7b873. Below is a detailed analysis of the patch:

Key Changes in PQescapeStringInternal()

– size_t remaining = length; + size_t remaining = strnlen(from, length); while (remaining > 0) { char c = *source; – int len; + int charlen; // Fast path for plain ASCII if (!IS_HIGHBIT_SET(c)) { *target++ = c; source++; remaining–; continue; } // Handle multi-byte characters charlen = pg_encoding_mblen(encoding, source); + if (remaining < charlen) { + if (error) + *error = 1; + if (conn) + libpq_append_conn_error(conn, "incomplete multibyte character"); + pg_encoding_set_invalid(encoding, target); + target += 2; + break; + } // Validate multi-byte character if (pg_encoding_verifymbchar(encoding, source, charlen) == -1) { if (error) *error = 1; if (conn) libpq_append_conn_error(conn, "invalid multibyte character"); pg_encoding_set_invalid(encoding, target); target += 2; source += charlen; remaining -= charlen; continue; } // Copy valid multi-byte character for (int i = 0; i < charlen; i++) { *target++ = *source++; remaining–; } }

Key Fixes

  1. Validation of Multi-byte Characters: The patch introduces a check to ensure that multi-byte characters are valid and complete before processing.
  2. Error Handling: Invalid or incomplete multi-byte characters are replaced with a guaranteed invalid sequence, ensuring that the server rejects the input.
  3. Improved Buffer Management: The patch ensures that buffer overflows and underflows are avoided by carefully managing the remaining input length.

Exploitation Techniques

Exploit Scenario

An attacker can exploit this vulnerability by:

  1. Crafting malicious input with invalid multibyte characters.
  2. Passing the input to an application that uses the vulnerable escaping functions.
  3. Triggering SQL injection or arbitrary code execution via psql.

Proof of Concept (PoC)

Below is a theoretical PoC for exploiting the vulnerability taken from here:

SELECT lo_export(
  (SELECT convert_from(pg_read_file('/etc/passwd'), 'UTF8')), 
  '/tmp/payload'
);

This input could bypass escaping and execute unintended SQL commands.

A public exploit for an RCE is already available here.

Mitigation Strategies

Immediate Actions

  1. Upgrade PostgreSQL: Update to the latest patched versions:
    • PostgreSQL 17.3, 16.7, 15.11, 14.16, or 13.19.
  2. Validate Input: Implement strict input validation to reject invalid multibyte characters.

Long-Term Recommendations

  • Use Parameterized Queries: Avoid constructing SQL queries using string concatenation.
  • Monitor Logs: Regularly review logs for suspicious activity, such as unexpected SQL commands.

How can ARMO help?

As ever, ARMO advocates a multi-layered security approach. ARMO provides capabilities in posture management and in runtime. It provides the in-depth visibility that serves the layered security required for cloud-native applications and infrastructure.

  1. Continuous scanning for vulnerabilities of your software packages:
    ARMO Platform’s continuous scanning capabilities provide a proactive defense against vulnerabilities like CVE-2025-1094. Regularly scanning your software packages and container images, identifies known vulnerabilities, and gives you information about the patched version. Thus, allowing you to swiftly address vulnerabilities and maintain a strong security posture.
  1. Detect in runtime if someone is exploiting this vulnerability utilizing ARMOs CADR:
    Runtime security is crucial for preventing exploitation attempts. ARMO CADR deep runtime analysis and explainability, identifies suspicious SQL payloads and anomalous behavior, flagging potential injection attempts in real-time.

We provide a python script to check if you are vulnerable to it, check it out here.

Shared Responsibility

Cloud providers like Amazon, Azure, and Google Cloud offer managed PostgreSQL services, and their promise is to handle the infrastructure and patching of the underlying database engine. That is where their responsibility ends. It is your responsibility to actively apply these patches. This step is crucial to ensuring that the vulnerability is effectively mitigated within your specific environment. Proactive security management is required even in cloud-based deployments.

Timeline of Discovery and Disclosure

DateEvent
January 27, 2025Rapid7 reports the vulnerability to the PostgreSQL security team.
January 29, 2025PostgreSQL confirms the vulnerability and assigns a CVE ID.
February 11, 2025PostgreSQL releases patched versions.
February 13, 2025Public disclosure of the vulnerability.

References

Final words

The discovery of CVE-2025-1094 provides a valuable, albeit concerning, lesson in the ongoing evolution of cybersecurity. It highlights the importance of continuous vigilance and the need to challenge assumptions about established security measures. Beyond immediate patching recommended above, organizations should prioritize long-term strategies. These include regular security audits, robust input validation, and the adoption of secure coding practices. By embracing a proactive and adaptive security posture, we can better protect our systems from emerging threats and build a more resilient digital landscape.

Close

Join the First Cloud Runtime Security Summit

Save your Spot city
slack_logos Continue to Slack

Get the information you need directly from our experts!

new-messageContinue as a guest