December 3, 2025·4 min read·engineeringpostgresqlsecurityauthentication

PgBouncer 1.25.1 fixes search path influence during authentication

CVE-2025-12819 lets unauthenticated startup state influence authentication SQL in specific configurations. Even an ordinary comparison operator can depend on PostgreSQL's schema search path.

Authentication code sometimes executes a database query before deciding whether a client may connect. That query must not resolve its functions and operators using authority supplied by the unauthenticated client. PgBouncer 1.25.1 fixes a path where a client-provided search_path could influence SQL executed during authentication.

The December 3 announcement identifies the problem as CVE-2025-12819. Its configuration conditions are specific. The deployment must track search_path through track_extra_parameters, use a nonempty auth_user, and have an authentication query containing names that are not fully qualified. The announcement explicitly includes the default query's unqualified comparison operator in the last condition.

I still default to PostgreSQL for relational systems, and its extensibility is one reason. The same extensibility makes SQL name resolution a security concern. A comparison that appears to use fixed built-in behavior can invoke a database object selected through session state.

The startup packet arrives before the identity is accepted

The configuration reference at the 1.25.1 tag describes tracking extra parameters in a client variable cache and restoring them on the server when that client becomes active. It supports parameter settings supplied directly in startup packets and through the startup options field.

Only parameters reported by PostgreSQL can be tracked this way. The reference notes that extensions can extend the reported set, including Citus reporting search_path. Tracking such state has a legitimate purpose when a pooler changes which backend connection serves a client. It allows the selected connection to reflect the client's session requirements.

Authentication creates a different context. The pooler performs work under an identity authorized to look up credentials before accepting the requesting identity. The December advisory describes the failure that results when client-controlled name-resolution state affects that work. A parameter useful after authentication can still be inappropriate input to the authentication query itself.

Schema lookup determines executable behavior

PostgreSQL's schema reference explains that unqualified names use the search path. It warns that including a schema in the path effectively trusts people allowed to create objects there. This behavior applies to functions and operators as well as tables.

The built-in catalog is normally searched implicitly before explicitly listed schemas when it is absent from the path. PostgreSQL also permits it to be named later in an explicit path, allowing user-defined names to take precedence. A security analysis therefore needs the effective lookup rules, rather than an assumption that a familiar spelling always identifies a built-in implementation.

The CREATE OPERATOR reference documents operators as schema objects backed by functions. Operators can share a name when their argument types differ. The symbol's appearance in SQL does not by itself identify the function that will execute.

That is the detail most easily missed in this disclosure. Qualifying the table name in an authentication query does not automatically qualify the comparison used against that table. Every executable object reference relevant to the query needs a resolution rule consistent with the trusted authentication context.

Operators have a qualification syntax

The operator-resolution documentation describes choosing candidates by name, argument count and visibility in the search path. With a qualified operator name, only operators in the named schema are considered. Argument types then determine which candidate matches.

PostgreSQL uses OPERATOR(schema.operator) to make that qualification explicit. A small expression illustrates the syntax without constructing an attack or changing authentication configuration:

SELECT 3 OPERATOR(pg_catalog.+) 4;

The schema reference uses this form because ordinary dotted operator syntax would be ambiguous. For a reader examining authentication SQL, punctuation therefore deserves the same attention as table and function names. An unqualified less-than operator remains an object lookup even if every column reference appears unsurprising.

This explanation follows PostgreSQL's documented resolution rules and the advisory's explicit reference to the default comparison. It does not imply that every custom operator is malicious or that every pooler using an authentication query is vulnerable. The listed PgBouncer configuration conditions still determine the disclosed path.

Credential lookup runs with its own privileges

The versioned PgBouncer reference says auth_user supplies the identity used to query credentials for users absent from auth_file. Direct access to pg_authid requires administrative rights. It recommends a non-superuser calling a security-definer function as a narrower alternative.

The PostgreSQL function reference explains that a security-definer function executes with its owner's privileges. It recommends a search path that excludes schemas writable by untrusted users, alongside controlled execution grants. Such a function is privileged code even when its visible purpose is only to return authentication information.

This makes the source of session state material. The requesting client has not yet established the right to become the requested database identity. Its supplied path cannot be treated as trusted merely because the pooler successfully parsed the startup message. Parsing establishes the parameter's representation, while authorization determines whether that parameter may influence privileged work.

I find that separation useful when reviewing pooler behavior. A working credential query is still executable SQL, and its effective session context is part of its meaning. The authentication boundary includes both the query text and the state under which PostgreSQL resolves it.

The maintenance release includes other authentication repairs

The 1.25.1 changelog shipped with the release also fixes ad hoc SCRAM authentication after reconnecting to a server and repairs parsing of SCRAM server messages. It identifies those regressions as introduced in 1.25.0. They are separate from the configuration-dependent SQL injection.

The December security correction is consequently a PgBouncer update, not a PostgreSQL server-version claim. Its affected workflow combines tracked startup state with a credential lookup under another identity. Operators evaluating exposure need the effective tracking configuration and authentication query, including any function called by that query. Those artifacts describe whether unauthenticated name-resolution state can reach the privileged work identified by CVE-2025-12819.