Hi,
HAProxy 2.8.28 was released on 2026/08/27. It added 47 new commits
after version 2.8.27.
This fixes a lot of issues, and a sizeable share of them were found
and reported with the help of AI-based tools/agents (Claude, OpenAI, and
a couple of other AI-assisted researchers), which seems to be an efficient way
to dig up this kind of corner case, so thanks to everyone involved for the
reports. A few areas received more attention than others and are worth
upgrading for:
- CVE-2026-78120: a TLS session established on one "bind" of an HAProxy
process could be resumed on a different "bind" of that same process,
regardless of the certificate or the client-certificate verification policy
configured on it.
With stateful resumption (the shared session cache), this worked between
any two binds of the process.
With stateless resumption (tickets), it worked between any binds sharing
the same tls-ticket-keys, even on a different process. By default,
tls-ticket-keys are generated randomly per bind, so this doesn't apply
unless the same keys are explicitly shared across binds.
In practice this meant a session/ticket obtained on a bind with no
client-certificate requirements could be resumed on another bind enforcing
strict mutual TLS, without the client ever presenting a certificate on that
second connection.
Configurations that gate access by checking whether a certificate was
actually used, rather than trusting the bind's handshake verification
result, were not affected: ssl_c_used correctly reflects certificate usage
on the current connection, whether resumed or not. As a mitigation without
upgrading, this can be enforced in TCP mode:
tcp-request content reject if ! { ssl_c_used }
or in HTTP mode:
http-request deny if ! { ssl_c_used }
Alternatively, the stateful session cache can be disabled entirely, leaving
stateless resumption -- whose tls-ticket-keys are randomly generated per
bind by default -- as the only resumption mechanism:
global
tune.ssl.cachesize 0
Note that, independently of this issue, it is good practice to inspect
the certificate presented by the client, as explained on the wiki:
https://github.com/haproxy/wiki/wiki/mTLS-configuration-in-HAProxy#inspecting-the-client-certificate
Three fixes now scope session/ticket resumption to the actual
certificate, verification policy and crt-list filter in use.
- tune.ssl.lifetime wasn't being enforced across TLS 1.3 session renewals
(including on AWS-LC), letting a resumed/renewed session outlive the
configured limit.
- CVE-2026-78121: qpack_get_varint(), used to decode QPACK-encoded HTTP/3
header fields, could shift a 64-bit value by 63 bits or more when parsing a
varint with an excessive number of continuation bytes, which is undefined
behavior in C. Impact is low: this was filed as BUG/MINOR since no
exploitable consequence beyond the UB itself was identified on the
compilers/platforms tested. The shift count is now explicitly bounded
before use.
- On top of this, a lot of other smaller fixes were made, please refer to the
complete changelog below for the details.
Upgrading is recommended for everyone running 2.8, especially those relying on
client certificate authentication.
Please find the usual URLs below :
Site index : https://www.haproxy.org/
Documentation : https://docs.haproxy.org/
Wiki : https://github.com/haproxy/wiki/wiki
Discourse : https://discourse.haproxy.org/
Slack channel : https://slack.haproxy.org/
Issue tracker : https://github.com/haproxy/haproxy/issues
Q&A from devs : https://github.com/orgs/haproxy/discussions
Sources : https://www.haproxy.org/download/2.8/src/
Git repository : https://git.haproxy.org/git/haproxy-2.8.git/
Git Web browsing : https://git.haproxy.org/?p=haproxy-2.8.git
Changelog : https://www.haproxy.org/download/2.8/src/CHANGELOG
Dataplane API :
https://github.com/haproxytech/dataplaneapi/releases/latest
Pending bugs : https://www.haproxy.org/l/pending-bugs
Reviewed bugs : https://www.haproxy.org/l/reviewed-bugs
Code reports : https://www.haproxy.org/l/code-reports
Latest builds : https://www.haproxy.org/l/dev-packages
---
Complete changelog :
Amaury Denoyelle (3):
BUG/MINOR: server: check strdup return value on server ID
BUG/MINOR: proxy: fix default-server leak on post-parsing cleanup
BUG/MEDIUM: quic: prevent out-of-bound read on wrapping CRYPTO content
Aurelien DARRAGON (1):
BUG/MEDIUM: lua: resume Channel:send() from the unsent part of the string
Austin Kauffman (1):
BUG/MINOR: fcgi-app: allow explicit filter declaration with
non-cache/non-compression filters
Christopher Faulet (3):
BUG/MEDIUM: filter: Disable auto-close on channel during TCP payload
filtering
BUG/MINOR: config: Check buffer pool creation for failures
BUG/MINOR: flt-http-comp: Don't read next block to detect end of data
Frederic Lecaille (1):
BUG/MINOR: qpack: missing shift count check in qpack_get_varint() (UB)
Mani Goyal (1):
BUG/MEDIUM: http: fix authority parsing for absolute-form URI with empty
path
Manu Nicolas (1):
BUG/MINOR: resolvers: accept fields at the response boundary
Miroslav Zagorac (1):
BUG/MINOR: ot: removed dead code in flt_ot_parse_cfg_str()
Olivier Houchard (8):
BUG/MINOR: cli: use the current argument to parse the FD spec in "show fd"
BUG/MINOR: mux-fcgi: don't call fcgi_strm_destroy() on a NULL stream
BUG/MEDIUM: sock: bound the recvmsg() length when receiving old sockets
BUG/MEDIUM: http-ana: check the cookie rewrite result before moving the
offsets
BUG/MINOR: mux-fcgi: sanitize the STDERR records before logging them
BUG/MEDIUM: bwlim: fix a stick-table entry leak in shared mode
BUG/MEDIUM: mux-fcgi: check the room left before appending the index
MEDIUM: mux-h2: don't report EOM on a short content-length message
Remi Tricot-Le Breton (2):
BUG/MINOR: conn: Do not check 'sess_el' list on frontend connections in
__trace_enabled
BUG/MINOR: ssl: release the previous client cert reference at depth > 0
William Lallemand (11):
BUG/MINOR: ssl: reject server certificate names containing a NUL byte
DOC: config: clarify req.ssl_sni
BUG/MINOR: payload: fix handshake length off-by-4 in ssl_hello_sni/alpn
BUG/MINOR: spoe: check snprintf() return value in
spoe_set_var/spoe_unset_var
BUG/MEDIUM: ssl: enforce tune.ssl.lifetime across TLS1.3 session renewals
BUG/MINOR: ssl: apply tune.ssl.lifetime to TLS1.3 sessions on
BoringSSL/AWS-LC
BUILD: ssl: disable the TLS1.3 session timeout clamp on wolfSSL
BUG/MEDIUM: ssl: isolate TLS session resumption per X509 server
certificate
BUG/MINOR: ssl: isolate TLS session resumption per crt-list filter
BUG/MEDIUM: ssl: isolate TLS session resumption per authentication policy
BUILD: ssl: avoid a potential null-dereference warning on OpenSSL 1.0.2
Willy Tarreau (13):
BUG/MEDIUM: hpack: encode long methods and schemes using the long form
BUG/MINOR: hlua: use a local buffer to format the socket addresses
BUG/MINOR: connection: reserve the whole CRC32C TLV before saving its
pointer
BUG/MINOR: lb-chash: bound the walk when the saved cursor changed tree
BUG/MINOR: mux-h2: strip the userinfo when deriving :authority for a
server
BUG/MINOR: http-fetch: fix smp_fetch_hdr_ip()'s handling of brackets for
IPv6
BUG/MINOR: http-fetch: make http_first_req() check for HTTP first
BUG/MINOR: http-act: set-status() must check the response message, not
the request
BUG/MINOR: tools: fix memory leak in env_expand() error path
BUG/MINOR: auth: free user groups on error paths in userlist_postinit()
BUG/MINOR: cfgcond: make KQUEUE check for GTUNE_USE_KQUEUE not
GTUNE_USE_EPOLL
BUG/MINOR: mux-h2: harden h2_dump_h2s_info() against potentially null
h2s->sd
BUG/MEDIUM: cache: ignore cache on redundant origin/referer
scientiamobile (1):
BUG/MINOR: wurfl: fix memory leak of information list and patch strings
at deinit
---
--
William Lallemand