PgBouncer 1.26.1:知道一个 SCRAM 用户密码就能登成超级用户,1.26.0 还静默改了 search_path 的默认跟踪
PgBouncer 1.26.1(2026-10-14,发布名 “Only startup once”)修了三个 CVE,另有一处配置优先级修正。三个 CVE 的影响面差别很大:认证绕过看账号策略,DoS 看配置列表,整数溢出看一个很少改的参数。配置修正是另一种问题:升级后不报错,只会让原本生效的忽略列表静默失效。
- 公告:https://www.pgbouncer.org/2026/10/pgbouncer-1-26-1
- Changelog:https://www.pgbouncer.org/changelog
- 发布包:https://github.com/pgbouncer/pgbouncer/releases
CVE-2026-107350(CVSS 8.8):认证绕过,影响 1.17.0 至 1.26.0
客户端连接一个不存在的数据库时,PgBouncer 在 SCRAM 认证过程中还会处理第二条 StartupMessage,并且不拒绝。知道 auth_file 中某个用户密码的攻击者,可以用这个密码登录成任意其他使用 SCRAM 认证的用户,包括 PgBouncer 管理用户和后端超级用户。前提是这两个用户都使用 SCRAM 认证;被冒充的用户可以来自 auth_file,也可以来自 auth_query。
问题本质:SCRAM 交换仍然用第一个用户的 key 校验,但登录身份已经被第二条 StartupMessage 切换。口令对得上、身份已换人。
对运维的含义是,只要能连到 PgBouncer 端口、掌握 auth_file 里任何一个 SCRAM 账号的口令,就可能拿到管理台或后端超级用户。所以先查看 auth_file 里到底还有哪些账号,尤其是低权限、弱口令、早已没人用的那批:
grep -vE '^\s*(;|#|$)' /etc/pgbouncer/userlist.txt | cut -d'"' -f2 | sort -u
管理台里确认当前版本:
psql -h 127.0.0.1 -p 6432 -U pgbouncer pgbouncer
SHOW VERSION;
版本落在 1.17.0–1.26.0 之间的,按 1.26.1 的发布说明升级。
CVE-2026-107349(CVSS 7.5):未认证 DoS,影响 1.20.0 至 1.26.0
startup 的 options 参数里带空选项名(例如 -c=),会让 ignore_startup_parameters 的列表查找进入死循环。触发条件是:ignore_startup_parameters 非空,且列表中不含 options。PgBouncer 是单进程服务所有客户端,一个核被占满后所有池化连接不可用,只能重启进程。
先看这行配置:
grep -n '^ignore_startup_parameters' /etc/pgbouncer/pgbouncer.ini
如果这行非空且不含 options,就是可触发状态。无法立即升级时,把 options 加进列表即可避开这条触发路径。升级到 1.26.1 后,这个问题本身已被修复。
CVE-2026-107348(CVSS 5.9):整数溢出致死循环,影响 1.21.0 至 1.26.0
消息缓冲区扩容逻辑 mbuf_make_room 存在整数溢出。仅当 max_packet_size 配置为 2147483649 或更高时受影响,默认值 2147483647 不在范围内。自 1.23.0 起,可以在认证之前用 5 字节包头触达该路径。与 CVE-2026-6668 同类,但落在另一套缓冲区实现里。
检查这个参数有没有被调大过:
grep -n 'max_packet_size' /etc/pgbouncer/pgbouncer.ini
管理台里一次看到实际生效值:
SHOW CONFIG;
生效值大于等于 2147483649 的,要么升级到 1.26.1,要么调回 2147483647。
配置修正:ignore_startup_parameters 现在优先于 tracked parameters
1.26.0 起 search_path 默认被跟踪(PostgreSQL 18+),结果 ignore_startup_parameters = search_path 静默失效——配置还在,行为变了,日志里没有提示。1.26.1 改为让 ignore_startup_parameters 优先于 tracked parameters,把 search_path 加进这个列表即可恢复 1.25 的忽略行为。围绕 search_path 跟踪的其它 bug 会在后续版本修。
升级后请确认两处同时成立:
grep -nE '^\s*(ignore_startup_parameters|track_extra_parameters)' /etc/pgbouncer/pgbouncer.ini
SHOW CONFIG;
从 1.25 升上来的实例,如果业务依赖“客户端 SET search_path 不进入服务端连接复用”,就要在 ignore_startup_parameters 中显式列出 search_path,不能假设旧配置继续生效。
升级前还要改一处脚本:-R 已经没了
1.26.0(2026-09-23)移除了废弃的 online restart(-R,takeover),以及只为它存在的 SHOW FDS、SUSPEND,改用 so_reuseport 的滚动重启。老部署脚本里带着 -R 的,升级后会直接启动失败。
先找出来:
grep -rn -- '-R' /etc/systemd/system/pgbouncer*.service /etc/init.d/pgbouncer 2>/dev/null
再改成多实例共享端口、逐个替换的方式:
[pgbouncer]
so_reuseport = 1
滚动重启时保证同一时刻至少有一个进程在监听,逐个向旧进程发 SIGTERM,由服务管理器拉起新进程接管连接。脚本里凡是依赖 SHOW FDS 做 fd 传递的步骤,都要一并删掉。
1.26.0 的其余变更
- 默认跟踪 PostgreSQL 报告的所有参数,最显著的是
search_path(PG18+)与default_transaction_read_only(PG14+)。此前在 transaction pooling 模式下,客户端执行SET search_path或SET default_transaction_read_only = true会影响之后复用同一 server 连接的其他客户端。 - 新增
pool_idle_timeout(默认关闭,回收长期未用的池;代价是丢统计)。 query_wait_timeout可按 user/database 配置。SHOW STATS新增client_login_count。- 登录时向客户端发送 PgBouncer 自有的 ParameterStatus:
pgbouncer.version、pgbouncer.pool_mode、pgbouncer.max_prepared_statements。 - 新增
login_notify_message,登录成功后以 NOTICE 通知客户端处于 PgBouncer 之后。 - 支持 meson 构建。
同版本还修了 CVE-2026-19888(未校验 SCRAM client-final-message 的 nonce,未认证者可崩溃)、CVE-2026-6668(缓冲区整数溢出死循环)、CVE-2026-6669(不限制服务端给来的 SCRAM 迭代次数,上限现为 1000000)。
此外修复了:transaction pooling 下迟到的 COPY 消息导致池耗尽;SCRAM pass-through 在 server 重连后失败(报 password is SCRAM secret but client authentication did not provide SCRAM keys);跨包边界时 TLS 连接卡住等。
参考
- PgBouncer 1.26.1 公告:https://www.pgbouncer.org/2026/10/pgbouncer-1-26-1
- Changelog:https://www.pgbouncer.org/changelog
- GitHub Releases:https://github.com/pgbouncer/pgbouncer/releases
- PostgreSQL 新闻:https://www.postgresql.org/about/news/pgbouncer-1261-released-fixes-three-cves-3403/