Hi,

HAProxy 3.0.27 was released on 2026/08/27. It added 69 new commits
after version 3.0.26.

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.

  - the "sink"/log forwarding code and the ring reader-attachment code
    received 2 fixes: attaching a reader to a ring used to isolate the
    thread while the sink forwarding applet held a lock, which could
    deadlock -- the ring code no longer isolates for this and takes the
    tail lock instead; and a new implicit ring could get created for each
    copy of a logger, which was a waste of memory and could confuse "show
    events".

  - when a message's body was shorter than its announced Content-Length, the H1
    mux still reused the connection and the H2 mux still marked the message as
    complete, silently forwarding a truncated message and risking confusion
    with the next request on a reused connection; the H1 mux now closes the
    connection instead, and the H2 mux no longer marks the message as complete.

  - the cache code got 3 fixes: an entry could be released while still
    referenced under the cache read lock, a secondary entry could be retained
    without its primary one when detaching a row, and a request with a
    duplicated Origin or Referer header could match a secondary key computed
    from only the first occurrence, so such requests now bypass the cache
    instead of risking an unpredictable match.

  - a handful of correctness fixes: an absolute-form request-target with no
    path but a query string (e.g. "http://host?token=...";) had its query string
    swallowed into the authority, corrupting the request on the wire; rewriting
    a server-side cookie ("cookie ... rewrite" or "prefix") could silently fail
    to expand and still corrupt the byte following it in the response; a TCP
    payload filter could lose buffered data if the producer shut its connection
    while the filter still had pending data to flush; Lua's Channel:send()
    could resend the same prefix instead of the remainder after a partial
    write, duplicating data and desynchronizing the stream; HPACK could
    truncate H2 request methods/schemes longer than 127 bytes, which in
    practice mostly caused shared backend connections to be aborted with a
    protocol error under "http-reuse always"; and the "aes_gcm_dec" converter
    accepted a truncated authentication tag instead of requiring the full 16
    bytes, which is now enforced.

Upgrading is recommended for everyone running 3.0, 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/3.0/src/
   Git repository   : https://git.haproxy.org/git/haproxy-3.0.git/
   Git Web browsing : https://git.haproxy.org/?p=haproxy-3.0.git
   Changelog        : https://www.haproxy.org/download/3.0/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 (4):
      MINOR: tools: add strnlen2() helper
      MINOR: log/tools: fix ambiguous comments for some log encoding helpers
      BUG/MEDIUM: log: always reserve room for trailing 0 when using CBOR 
encoding helpers
      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 (2):
      BUG/MINOR: server: fix off-by-one error when parsing and copying source 
port range
      BUG/MINOR: qpack: missing shift count check in qpack_get_varint() (UB)

Kirill Furman (1):
      BUG/MINOR: log: fix double-free error when error in parse_loger occurs

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 (10):
      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: stick-tables: use the same bucket for string keys with a NUL
      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
      BUG/MEDIUM: mux-h1: close the connection on a short content-length
      MEDIUM: mux-h2: don't report EOM on a short content-length message

Remi Tricot-Le Breton (4):
      BUG/MEDIUM: ssl: require a full-length AEAD tag when decrypting with 
AES-GCM
      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
      BUG/MEDIUM: ssl: Fix unprotected 'ssl_sock_choose_sni_ctx' calls

Rémi Tricot-Le Breton (2):
      BUG/MEDIUM: cache: retain the primary or secondary entry only when 
detaching its row
      BUG/MEDIUM: cache: do not release an entry under the cache read lock

William Lallemand (13):
      BUG/MINOR: ssl: reject server certificate names containing a NUL byte
      DOC: config: clarify req.ssl_sni
      BUG/MINOR: ssl: reject an embedded NUL in the ssl_*_dn(entry) fetches
      BUG/MINOR: ssl: reject an embedded NUL in the full-DN ssl_*_dn() fetches
      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 (22):
      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/MEDIUM: session: don't release a reversed connection twice on error
      BUG/MINOR: lb-chash: bound the walk when the saved cursor changed tree
      BUG/MINOR: debug: only dump the trace once in __BUG_ON_ONCE()
      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: mqtt: connack parser returns MQTT_NEED_MORE_DATA on unknown 
property
      BUG/MINOR: mqtt: connect parser uses wrong bit field for 
TOPIC_ALIAS_MAXIMUM
      BUG/MINOR: mqtt: connack parser uses wrong bit for 
SUBSCRIPTION_IDENTIFIERS_AVAILABLE
      BUG/MINOR: mqtt: fix PUBLISH flags validation that want all bits to be set
      BUG/MINOR: mux-h2: harden h2_dump_h2s_info() against potentially null 
h2s->sd
      BUG/MEDIUM: connection: fix an infinite loop in the fc_pp_tlv() fetch
      MEDIUM: ring: attach readers under the tail lock instead of isolating
      BUG/MEDIUM: cache: ignore cache on redundant origin/referer
      BUG/MEDIUM: sink: do not create one implicit ring per logger copy

scientiamobile (1):
      BUG/MINOR: wurfl: fix memory leak of information list and patch strings 
at deinit

---

-- 
William Lallemand


Reply via email to