Hi, HAProxy 2.6.30 was released on 2026/06/26. It added 49 new commits after version 2.6.29.
HAProxy 2.6 is in "critical fixes only" maintenance mode. So this release is lighter than the other recent releases. Notably, most QUIC and HTTP/3 fixes were not backported: the QUIC stack remains experimental in 2.6, the backport risk is high, and the risk of introducing regressions outweighs the benefits for the small number of users running QUIC on such an old branch. Production deployments requiring QUIC support should migrate to a more recent branch such as 3.2. Only one isolated QUIC mux draining fix was retained, along with a few QPACK decoder fixes that apply to a shared code path. The HTTP/1 parser received a fix to filter out all "h2c" values from Upgrade headers during parsing, preventing protocol confusion when a client sends unsupported upgrade requests. The WebSocket protocol token is no longer masked when multiple protocols appear in the Upgrade header. A large number of bugs were fixed in the DNS resolver code. A validation bug was fixed in resolv_read_name() where a name compression pointer was not validated against the response bounds, potentially causing out-of-bounds memory reads when processing crafted DNS responses. A bug in resolv_dn_label_to_str() were fixed: the label size check used an incorrect comparison. A related fix prevents garbage data from being appended past the domain name. A memory leak of a sockaddr structure was fixed in the dns_session_init() error path. Minor error-path fixes addressed a dangling pointer on dns_dgram_init() failure, and the do-resolve() action parser now properly reports expression errors. In the FCGI multiplexer, an integer overflow was fixed: the unsigned 16-bit integer used for the record length overflowed to 0 when the record length was 65535 and padding was non-zero, causing the state machine to skip consuming buffer data and parse the remaining bytes as a new FCGI record header. This could only happen for unknown records or for STDOUT records received after the end of the response. CVE-2026-55203 was assigned to this overflow. It must be noted however that the assigned severity is excessively high relative to the actual exploitability: triggering this bug requires the FCGI backend server itself to be compromised and to craft a malicious response with exactly those values, which is well outside a normal threat model where the backend is trusted. Additionally, stream ID 0 was not rejected for application records as required by the FCGI specification, potentially causing incorrect demultiplexing. When trying to forward data to a server whose stream was already closed, the FCGI mux claimed to have consumed buffered data without actually draining them, causing the upper layer to loop endlessly trying to send. A minor fix also corrected the computation of contiguous data in the demux buffer. Several bugs were fixed in the H1 and H2 multiplexers. In the H1 mux, the connection/upgrade header value is now duplicated before being parsed when building outgoing request headers, as the parsing modified the value in-place and could corrupt shared data. The 'h1-case-adjust-file' directive was not resolving a relative file path to an absolute path at parse time, causing failures when multiple configuration files were loaded. A possible failure from strdup() was also left unhandled. In the H2 mux, when forwarding data to a server whose stream was already closed, the mux claimed to have consumed buffered data without actually draining them; this could cause the upper layer to keep retrying in a loop and potentially trigger the watchdog. The HEADERS frame length is now also validated before reading the stream dependency field. One fix was applied to the QUIC multiplexer: an issue in qcs_http_reset_buf() caused the entire buffer to be reset unconditionally instead of draining only the requested amount, which could silently discard unsent data when a stream filter was registered on the data forwarding stage. Several bugs were fixed in the QPACK decoder, which is shared between QUIC and other code paths. Index calculation in debug functions was incorrect. A potential null-pointer dereference was fixed in qpack_dht_insert() when the memory pool was exhausted. A sign bit mask was wrong in qpack_decode_fs_pfx(), potentially causing incorrect header value decoding. Error handling in huff_dec() called from qpack_decode_fs() was not properly propagating the error. Two bugs were fixed in the Lua integration. An integer underflow was possible in the Lua cosocket line-read path, causing memory corruption when fewer bytes than expected were received. Lua was also not filtering CR, LF, and NUL characters from HTTP headers set by scripts, which could allow header injection attacks. Two bugs were fixed in the cache subsystem. The primary hash was not always verified in get_secondary_entry(), which could lead to incorrect cache hits returning the wrong cached response. The maxage value was being overwritten instead of properly copied during parsing of cache-control directives. Two locking bugs were fixed in the dictionary subsystem, which is used internally for string deduplication. The read lock was not held while incrementing the refcount in dict_insert(), creating a race condition where two concurrent inserts could corrupt the refcount of a shared entry. The write lock was not held while decrementing the refcount in dict_entry_unref(), allowing a concurrent lookup to observe an inconsistent state and potentially access freed memory. A further race on insert collision was fixed where the refcount was not properly updated when two threads inserted the same key simultaneously. Several SSL/TLS fixes are included. With TLS 1.3 0-RTT, the early data buffer was freed when emptied but more early data could still arrive; the buffer is now reset rather than freed until all early data has been received, preventing use-after-free. SNI character validation was added to the dynamic certificate generation code to prevent SAN certificate injection through crafted SNI values. The null-terminated servername is now properly used in the SSL hello parser. A memory leak in the ECDSA signature conversion error path was also fixed. When L7 retries were configured and the maximum retry count was reached on a reused connection, the stream was silently closed on the client side instead of properly returning a 502 or 425 error, leaving the client without a meaningful response. The HTTP authentication token checker was not verifying against the whole token, allowing partial matches to succeed. The HTTP client CLI now properly destroys its context if it fails to start. Two health check bugs were fixed. External checks were not being excluded from the tcpcheck post-config phase, which could cause a NULL pointer dereference at startup. Additionally, when a server inherited ALPN settings from a default server, the health check was using a reference to the default server's ALPN string rather than a proper copy, which could lead to incorrect ALPN negotiation or unexpected behavior if the default server configuration was modified. A NULL pointer dereference was fixed in the HPACK table code: when the memory pool was exhausted, hpack_dht_defrag() could return NULL and be immediately dereferenced, crashing the worker process. CVE-2026-55204 was assigned to this issue. Here again the assigned severity is excessively high: the condition only arises when the process is already out of memory, at which point the allocator failure itself is likely to cause other problems before this specific code path is even reached. The probability of hitting this particular NULL dereference in a production environment is extremely thin. A NULL pointer dereference was fixed in the authentication code when an unconfigured password entry (NULL) was accessed during authentication, which could crash the process when a user with no password was configured. The log-forward module treated the month field as a signed integer, which could cause incorrect log timestamps when the high bit was set. Finally, a few other minor issues were addressed: the be2hex sample converter chunk size was not bounded, potentially causing oversized output; the client hello parser had incorrect bounds checks for the handshake length; the addons/51d module was not NUL-terminating headers before passing them to the Trie API; parameter value validation in get_server_ph_post() had an incorrect comparison; and consistent hash balancing for newly added servers was broken. Thanks to everyone for your help on this release! 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 Sources : https://www.haproxy.org/download/2.6/src/ Git repository : https://git.haproxy.org/git/haproxy-2.6.git/ Git Web browsing : https://git.haproxy.org/?p=haproxy-2.6.git Changelog : https://www.haproxy.org/download/2.6/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 (1): BUG/MINOR: server: fix add server with consistent hash balancing Christopher Faulet (18): BUG/MINOR: httpclient-cli: Destroy http-client context if failing to start it BUG/MEDIUM: h1: Skip all h2c values from Upgrade headers during parsing BUG/MINOR: h1: Don't mask websocket protocol if multiple protocols used BUG/MEDIUM: server: Duplicate healthcheck's alpn inherited from default server BUG/MEDIUM: resolvers: Fix test on dn label size in resolv_dn_label_to_str() BUG/MEDIUM: dict: hold lock while decrementing refcount in dict_entry_unref BUG/MEDIUM: hlua: Fix integer underflow when receiving line from lua cosocket BUG/MEDIUM: mux-fcgi: reject stream ID 0 for application records BUG/MINOR: mux-fcgi: Use relative offset to compute contig data in demux buf Revert "BUG/MEDIUM: dns: fix long loops in additional records parse on name failure" BUG/MINOR: cache: Fix copy of value when parsing maxage BUG/MEDIUM: mux-h1: Dup connection/upgrade value to parse it when making headers BUG/MEDIUM: check: Skip tcpcheck post-config for external checks BUG/MEDIUM: http-ana: Don't ignore L7 retry errors BUG/MINOR: mux-h1: Properly resolve file path for 'h1-case-adjust-file' BUG/MEDIUM: mux-fcgi: Truly drain outgoing HTX data when the stream is closed BUG/MEDIUM: mux-h2: Truly drain outgoing HTX data when the stream is closed BUG/MEDIUM: mux-quic: Drain the given amount of data in qcs_http_reset_buf() Frederic Lecaille (4): BUG/MINOR: qpack: Fix index calculation in debug functions BUG/MINOR: qpack: fix potential null-pointer dereference in qpack_dht_insert() BUG/MINOR: qpack: fix sign bit mask in qpack_decode_fs_pfx() BUG/MINOR: qpack: fix huff_dec() error handling in qpack_decode_fs() Ilia Shipitsin (1): BUG/MINOR: mux_h1: handle a possible strdup() failure Olivier Houchard (1): BUG/MEDIUM: ssl: Don't free the early data buffer too early Tristan Madani (2): BUG/MINOR: hpack-tbl: add missing NULL check after hpack_dht_defrag() BUG/MEDIUM: mux-fcgi: fix uint16_t overflow in drl += drp William Lallemand (2): BUG/MEDIUM: auth: fix unconfigured password NULL deref BUG/MINOR: ssl-gencert: validate SNI characters to prevent SAN certificate injection Willy Tarreau (20): BUG/MEDIUM: dict: hold read lock while incrementing refcount in dict_insert BUG/MINOR: backend: correct parameter value validation in get_server_ph_post() BUG/MEDIUM: dns: fix long loops in additional records parse on name failure BUG/MEDIUM: resolvers: fix name compression pointer validation in resolv_read_name() BUG/MEDIUM: dns: fix memory leak of sockaddr in dns_session_init() error path BUG/MINOR: dns: fix dangling dgram pointer on dns_dgram_init() failure path BUG/MINOR: resolvers: report the expression error in the do-resolve() action parser BUG/MINOR: jwt: fix possible memory leak in convert_ecdsa_sig() error path BUG/MEDIUM: log-forward: make sure the month is unsigned BUG/MINOR: resolvers: fix room for trailing zero in resolv_dn_label_to_str() BUG/MINOR: resolvers: fix risk of appending garbage past the domain name BUG/MINOR: mux-h2: validate HEADERS frame length before reading stream dep BUG/MINOR: dict: fix refcount race on insert collision BUG/MINOR: sample: limit the be2hex converter's chunk size BUG/MEDIUM: cache: always verify the primary hash in get_secondary_entry() BUG/MINOR: http-fetch: check against the whole token in get_http_auth() BUG/MINOR: payload: fix the handshake length bounds check smp_client_hello_parse() BUG/MINOR: ssl-hello: make use of the null-terminated servername BUG/MINOR: addons/51d: NUL-terminate headers before passing them to Trie API BUG/MINOR: hlua: prevent Lua from passing CR/LF/NUL in HTTP headers -- Christopher Faulet

