CVE-2025-2291 - PgBouncer "VALID UNTIL yesterday"
First Published: 2025/04/30
Last Updated: 2025/04/30
Important: This is an assessment of the impact of CVE-2025-2291 on EDB products and services. It links to and details the CVE and supplements that information with EDB's own assessment.
Summary
In PgBouncer, the auth_query
mechanism does not consider the VALID UNTIL
attribute set in PostgreSQL for user passwords.
This oversight allows users to authenticate using expired passwords, potentially granting unauthorized access. The flaw was fixed in PgBouncer 1.24.1.
Vulnerability details
CVE-ID: CVE-2025-2291
CVSS Base Score: 8.1
CVSS Temporal Score: Undefined
CVSS Environmental Score: Undefined
CVSS Vector: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H
Affected products and versions
- Community PgBouncer: All versions prior to 1.24.1
- EDB PgBouncer: All versions prior to 1.24.1
- EDB TPA: All versions prior to 23.38.0
- PGAI Cloud Service: All versions prior to May 12, 2025 release.
Remediation/fixes
Product | VRMF | Remediation/First Fix |
---|---|---|
Community PgBouncer | 1.24.1 | Upgrade to Community PgBouncer 1.24.1 |
EDB PgBouncer | 1.24.1 | Upgrade to EDB PgBouncer 1.24.1 |
EDB TPA | 23.38.0 | Upgrade to TPA 23.38.0 when available |
PGAI Cloud Service | May 12, 2025 | Resolved by May 12, 2025 Release |
For TPA we recommend applying the following mitigation measures until the upcoming version with a fix is available:
Two solutions are available:
The first and preferred solution is to create a postgres-config-final
hook that will be run at the end of the existing tpaexec deploy
command. The hook should be placed in the cluster directory under the hooks/
folder and should be named postgres-config-final.yml
, with the following content.
--- - name: Mitigate CVE-2025-2291 block: - name: Edit function pgbouncer_get_auth() and grant execute permissions postgresql_query: conninfo: "{{ dsn|dbname(item) }}" queries: - text: > CREATE OR REPLACE FUNCTION pg_catalog.pgbouncer_get_auth(p_usename TEXT) RETURNS TABLE(username TEXT, password TEXT) AS $$ BEGIN RETURN QUERY SELECT usename::TEXT, CASE WHEN valuntil < now() THEN NULL ELSE passwd::TEXT END FROM pg_catalog.pg_shadow WHERE usename = p_usename; END; $$ LANGUAGE plpgsql SECURITY DEFINER - text: REVOKE ALL ON FUNCTION pg_catalog.pgbouncer_get_auth(p_usename TEXT) FROM PUBLIC - text: GRANT EXECUTE ON FUNCTION pg_catalog.pgbouncer_get_auth(p_usename TEXT) TO "{{ pgbouncer_auth_user }}" changed_when: true become_user: "{{ postgres_user }}" become: yes with_items: "{{ cluster_facts.databases.keys()|list }}" vars: dbs: "{{ auth_function_dbs|default({}) }}" when: - item not in ['template0', 'bdr_supervisordb'] when: > postgres_users|json_query("[?username=='%s']" % pgbouncer_auth_user) != [] and task_selector|permits('pgbouncer')
Then you should run tpaexec deploy <cluster_dir>
to apply the changes.
This will modify the underlying function used by auth_query setting in PgBouncer to take password validity into account.
The second solution is to apply the same modification via a custom command:
The custom command file should be created as mitigate-CVE-2025-2291.yml
in the commands/
folder inside the TPA cluster directory with the following content:
--- - import_playbook: "{{ tpa_dir }}/architectures/lib/init.yml" tags: always - name: Perform custom command tasks hosts: all tasks: - name: Mitigate CVE-2025-2291 block: - name: Edit function pgbouncer_get_auth() and grant execute permissions postgresql_query: conninfo: "{{ dsn|dbname(item) }}" queries: - text: > CREATE OR REPLACE FUNCTION pg_catalog.pgbouncer_get_auth(p_usename TEXT) RETURNS TABLE(username TEXT, password TEXT) AS $$ BEGIN RETURN QUERY SELECT usename::TEXT, CASE WHEN valuntil < now() THEN NULL ELSE passwd::TEXT END FROM pg_catalog.pg_shadow WHERE usename = p_usename; END; $$ LANGUAGE plpgsql SECURITY DEFINER - text: REVOKE ALL ON FUNCTION pg_catalog.pgbouncer_get_auth(p_usename TEXT) FROM PUBLIC - text: GRANT EXECUTE ON FUNCTION pg_catalog.pgbouncer_get_auth(p_usename TEXT) TO "{{ pgbouncer_auth_user }}" changed_when: true become_user: "{{ postgres_user }}" become: yes with_items: "{{ cluster_facts.databases.keys()|list }}" vars: dbs: "{{ auth_function_dbs|default({}) }}" when: - item not in ['template0', 'bdr_supervisordb'] when: > "primary" in role
The playbook can be run using the command
tpaexec mitigate-CVE-2025-2291 .
References
Related information
Acknowledgement
Source: PostgreSQL Security Team
Change history
- 30 April 2025: First published version of the document.
Disclaimer
This document is provided on an "as is" basis and does not imply any kind of guarantee or warranty, including the warranties of merchantability or fitness for a particular use. Your use of the information on the document is at your own risk. EDB reserves the right to change or update this document at any time. Customers are therefore recommended to always view the latest version of this document.
Could this page be better? Report a problem or suggest an addition!