Recent development · Practical technical guide · 17 October 2026

PgBouncer 1.26.1, released 14 October 2026, fixes an authentication bypass and two denial-of-service bugs. Affected versions and preconditions from the changelog, a triage table, rolling-restart patching now that online restart is gone, and verification steps.

What was released

On 14 October 2026 the PgBouncer project released version 1.26.1. It fixes three CVEs and restores a configuration behaviour that 1.26.0 had changed. The most serious, CVE-2026-107350, is an authentication bypass: a client that knows the password of one SCRAM user could log in as any other SCRAM user, including administrators and backend superusers. The other two let an unauthenticated client put PgBouncer into an infinite loop under specific settings, which stops it serving every client because PgBouncer is single-threaded.

The details below come from the project's changelog and release announcement. Version ranges are exactly those the changelog states; this article does not extend them.

The three CVEs, with preconditions

CVEAffected versionsImpactExploitable only when
CVE-2026-1073501.17.0 through 1.26.0Log in as any other SCRAM user, including admins and superusersThe attacker knows the password of a user listed in auth_file, both users authenticate with SCRAM, and the client connects to a non-existent database, sending a second StartupMessage during SCRAM authentication. The impersonated user can come from auth_file or auth_query
CVE-2026-1073491.20.0 through 1.26.0Unauthenticated infinite loop, no clients servedignore_startup_parameters is non-empty but does not contain options, and the client sends an empty option name such as -c=
CVE-2026-1073481.21.0 through 1.26.0Infinite loop from an integer overflow in packet buffer growthmax_packet_size is set to 2147483649 or higher; the default 2147483647 is not affected. Reachable before authentication since 1.23.0

Read the first row carefully. The attacker needs a valid password for some user in auth_file, which sounds like a high bar until you count how many such users exist in a typical deployment: application accounts whose passwords sit in many services' configuration, monitoring users, shared read-only accounts. Any of those becomes a path to a superuser if the superuser also authenticates with SCRAM through the same PgBouncer.

Triage in the order that matters

  1. Inventory. List every PgBouncer instance and its version. Containers and sidecars are easy to miss; so are managed images that bundle PgBouncer.
  2. Check auth configuration. For each instance on 1.17.0 to 1.26.0, check auth_type and whether SCRAM users exist in auth_file or through auth_query. If yes, treat CVE-2026-107350 as critical for that instance.
  3. Check the two settings. Record ignore_startup_parameters and max_packet_size. Instances with an empty ignore list and the default packet size are not exposed to the two loop bugs, according to the stated conditions.
  4. Check exposure. Which networks can reach the PgBouncer port? An instance reachable from many workloads or from outside the cluster moves up the queue.
  5. Patch. Upgrade to 1.26.1. If you are on a version before 1.26.0, the upgrade also brings the three CVE fixes from 1.26.0, released 23 September 2026, including a pre-authentication crash in SCRAM handling.

Patching without downtime now that online restart is gone

PgBouncer 1.26.0 removed the deprecated online restart (-R, takeover) together with the SHOW FDS and SUSPEND admin commands. Runbooks that relied on it will fail. The changelog points to rolling restarts with so_reuseport instead: run several PgBouncer processes on the same port, then replace them one at a time, so new connections land on the processes still running while the one being replaced finishes its clients.

On Kubernetes, the equivalent is a rolling update of the PgBouncer Deployment with a preStop delay and a drain, as described in pod termination without dropped requests. In transaction pooling mode, clients reconnect transparently between transactions if their driver retries connection errors; test that before the production change.

If you cannot patch today

These are risk reductions derived from the preconditions above, not fixes, and each needs testing against your clients:

  • Restrict network access to PgBouncer to the workloads that need it.
  • Reduce the number of auth_file users, and rotate passwords for accounts whose credentials are widely distributed.
  • Avoid routing superuser and administrative logins through a PgBouncer that also serves many application accounts.
  • For CVE-2026-107349, the stated condition is a non-empty ignore list without options; review whether the ignore list is needed at all.
  • For CVE-2026-107348, return max_packet_size to its default or lower unless you know why it was raised.

The search_path behaviour change

1.26.0 began tracking every parameter PostgreSQL reports by default, notably search_path on PostgreSQL 18 and later, so that a client running SET search_path in transaction pooling mode no longer leaks the setting to other clients. As a side effect, ignore_startup_parameters = search_path silently stopped having any effect. 1.26.1 makes the ignore list take precedence over tracked parameters, so listing search_path there restores the 1.25 behaviour of ignoring it. The changelog also says other reported bugs around search_path tracking will be addressed in a later release. If you upgraded to 1.26.0 and saw search_path differences, re-test after 1.26.1.

Verify the fix

Illustrative python, checked for syntax; adapt names and storage to your system.

import psycopg

# PgBouncer 1.26.0 and later report themselves to clients at login.
with psycopg.connect("host=pgbouncer.internal port=6432 dbname=app user=app_ro") as conn:
    version = conn.info.parameter_status("pgbouncer.version")
    mode = conn.info.parameter_status("pgbouncer.pool_mode")
    print(version, mode)
    assert version is not None, "not connected through PgBouncer 1.26+"

Version 1.26.0 added ParameterStatus messages named pgbouncer.version, pgbouncer.pool_mode and pgbouncer.max_prepared_statements on login, so a client can confirm what it is talking to. Against older versions the value is absent, which is itself a finding. On the admin console, SHOW VERSION; and SHOW CONFIG; confirm the version and the two settings. Record the result per instance in the same inventory you built for triage.

Add one check to the image pipeline as well: run pgbouncer --version inside every PgBouncer image during CI and fail the build below 1.26.1. Without it, an image rebuilt later from a stale base or an old package mirror can quietly bring 1.26.0 back, and the runtime check above would only notice after deployment.

Looking for past exploitation

The changelog does not describe log signatures, so be careful about what you conclude. A reasonable review looks for login attempts to database names that do not exist, from the same client address shortly before a successful login as a different and more privileged user, and for privileged sessions from addresses that normally only carry application traffic. Correlate PgBouncer logs with PostgreSQL connection logs, which record the user the backend actually authenticated. If you find a match, treat the impersonated account's activity as an incident.

The same week in the client stack

ReleaseDateSecurity content
PostgreSQL JDBC 42.7.14Announced 2026-10-07, posted 2026-10-09Two CVEs: CVE-2026-107314 and CVE-2026-107315; see the project release notes
psqlODBC 18.00.00052026-10-14CVE-2026-109448: heap memory corruption when binding more than 32767 parameters; versions 08.01.0102 through 18.00.0004

Patch these in the same window if you use them; connection poolers and drivers sit on every request path, and a single maintenance window for the client stack is easier to coordinate than three.

Sources and scope

Checked against these sources on 17 October 2026. Event: PgBouncer 1.26.1 release, 14 October 2026; recheck it before acting. Examples and figures are illustrative, not measurements.

Upgrade every PgBouncer to 1.26.1, prioritising SCRAM deployments, replace takeover restarts with rolling ones, and verify versions and settings per instance.