Hi,

HAProxy 3.2.24 was released on 2026/09/24. It added 62 new commits
after version 3.2.23.

This release fixes a number of bugs in the HTTP/3 and QUIC stacks, in the
HTTP message processing and in the Lua integration, along with several
smaller fixes and a startup failure when configuring "maxpipes" without
"maxconn".

* h3: Truncated HTTP/3 frames are now rejected.

  HTTP/3 connections are now rejected when a stream ends before all the
  bytes announced in a frame have arrived. Previously, an incomplete frame
  could be accepted, creating a risk of request-content smuggling when the
  request was forwarded. This is an important fix for deployments accepting
  HTTP/3 traffic. This issue was reported by Rajat Raghav.

  In relation to this issue, the H1 multiplexer was hardened so that an
  incomplete message can never be emitted to a server as a complete one:
  trailers are no longer sent while the last chunk is unfinished, and a
  connection on which the message body was not fully sent is now always
  closed instead of being reused, whether the body was announced with a
  Content-Length or chunked.

* quic: Connection and stream leaks on QUIC frontends were fixed.

  Two issues could prevent QUIC connections from being properly released.

  A client sending a RESET_STREAM frame as the very first frame of a stream
  left that stream half-closed and accounted forever: stream instances
  accumulated in memory for the whole lifetime of the connection, and the
  connection itself could refuse to close even after the idle timeout had
  expired. Such streams are now closed and purged immediately.

  Second, the connection timeout was only armed once the first bytes were
  received, so a connection on which nothing was ever received had no
  timeout at all and could linger indefinitely. "timeout client" is now
  armed from connection initialization, which guarantees that idle
  connections are always closed as expected, and further reduces the risk of
  leaked connections, including the case above.

* h3/qpack: Several stalled transfers and compliance issues were fixed.

  A transfer ending with an empty DATA frame, empty trailers, or an unknown
  extension frame could wait until timeout instead of completing. These
  cases now correctly signal the end of the message. Invalid empty headers
  are also handled according to the protocol.

  When HAProxy aborts an HTTP/3 request, notably a POST whose body is still
  arriving, it now reliably tells the client to stop sending. Previously,
  the stream could be released before this notification was sent, leaving
  the client sending data that HAProxy no longer needed.

  HTTP/3 header-compression control streams now release the space occupied
  by data already processed, rather than becoming permanently stalled.
  Invalid references to an unsupported dynamic compression table are also
  rejected more strictly. Finally, HTTP/3 frame counters no longer count a
  large frame several times just because it arrived in multiple pieces,
  making the reported statistics more reliable.

* quic: More robust key updates and error recovery.

  A failed memory allocation during a key update could cause a worker crash
  on a subsequent key-phase change. HAProxy now retries key preparation and,
  if necessary, drops the packet so that the peer can retransmit it, rather
  than using missing keys. Delayed packets from the initial key phase are
  also accepted correctly after the first key update, avoiding unnecessary
  packet loss and retransmissions on connections with reordered traffic.

  Error handling after the handshake now cleans up the correct connection
  identifiers and preserves their numbering for a retry. A small memory leak
  on token-generation failure has also been fixed. Additional defensive
  handling for ChaCha20 with AWS-LC is included, although its problematic
  cleanup path is not currently reachable.

* htx: Header length limits are now enforced on updates.

  A header name is limited to 255 bytes and a header value to 1 MB minus one
  byte. These limits were checked when a header was added, but not when an
  existing one was rewritten with "replace-header" or "replace-value"
  rules. When exceeded, the length silently overflowed into the block type,
  corrupting the message. Since the header must first fit in a buffer, only
  setups with "tune.bufsize" above 1 MB are affected; a client sending a
  large enough header is then enough to trigger the issue. The same checks
  are now applied on updates. The issue was reported by Adam Crawford.

  An additional HTTP message buffer fix was backported as a precaution, to
  prevent corruption when adding an empty block to a full buffer. Its only
  known trigger is the decompression filter which only exists in 3.5-dev, so
  no released version is known to be affected. The "tune.bufsize"
  documentation was also clarified regarding the 256 MB hard limit and the
  fact that the header-size limit applies to both requests and responses.

* cli: An out-of-bounds write in the command line parser was fixed.

  Reading another command or payload line into an already full buffer could
  cause a one-byte write past its end. HAProxy now detects the full buffer
  before attempting the read and reports an oversized command instead.  Only
  users with access to the Runtime API (stats socket) could trigger this
  issue; it is not exposed through normal proxied traffic. Unlike in 3.4,
  this branch does not have dynamically sized CLI payload buffers and is not
  affected by the related zero-sized allocation crash.

* hlua: A use-after-free in Lua cosockets was fixed.

  Garbage collection of Lua sockets could release resources from the wrong
  thread or access resources already freed, potentially crashing a worker.
  This notably affected scripts loaded with "lua-load", whose state is
  shared between threads. Socket cleanup is now handed back to the owning
  thread. Closing a Lua socket that was never connected is also safe.

  HTTP message duplication consistently returns nil when there is no data to
  copy. Finally, memory associated with Lua rules is released during
  configuration teardown; this was not a leak accumulating on each request
  during normal operation.

* ssl: TLS session resumption failures and several smaller issues were fixed.

  With OpenSSL 3.1 or older, resuming a TLS session at the end of its
  configured lifetime could fail with an internal-error alert instead of
  falling back to a full handshake. Expired sessions are now discarded
  correctly, allowing the connection to proceed with a fresh handshake while
  still respecting "tune.ssl.lifetime". Newer OpenSSL versions were not
  affected.

  On 64-bit big-endian systems such as s390x and ppc64, the AES decryption
  converters could corrupt memory and crash a worker when processing input.
  The output-length handling has been corrected. This particular issue does
  not affect the usual little-endian systems.

  A small memory leak when deleting CA-file entries has also been fixed.

* sample: Strings carrying an embedded NUL byte could bypass ACLs.

  The "url_dec", "json_query", "jwt_header_query" and "jwt_payload_query"
  converters could produce a string containing a NUL byte (from "%00",
  "\u0000" or a base64-decoded JSON). Such a string was then compared by "-m
  str" on its prefix only, so "/public%00/admin" matched "/public" and an
  allow-list could be bypassed. These converters now fail on such input,
  like they already do on invalid sequences. Legitimate URLs and tokens are
  not affected. Along with this, the configuration manual now describes the
  exact contents allowed for each sample type.

* map: A crash with map_regm inside an ACL was fixed.

  Using the "map_regm" converter in an ACL applied on a fetch that iterates
  over several values, such as "req.hdr(name)" without an occurrence number,
  crashed the process as soon as the first value did not match. The
  converter was overwriting the internal iteration cursor of the fetch. A
  single request was enough to trigger it, and the bug has existed since
  1.7. The issue was reported by @Michael-JRead.

* http rules: capture rules evaluated in the backend context could crash.

  Capture rules cannot be used on the backend side. However it is possible
  to have such rules on a listener. In that case, when the listener was used
  as a backend only, a crash could be experienced or the memory pools could
  be corrupted because the capture slots were used in the context of a
  frontend that never referenced them. Since such backend relationship can
  only be resolved at run time, this could not be detected at startup. The
  rules are now ignored for requests coming from another frontend, and the
  documentation was updated to state that these capture slots only exist in
  the section declaring them.

* http-htx: Rewriting the "Host" header of large requests could corrupt them.

  When a "replace-header" rule rewrites the "Host" header of a request whose
  URI contains an authority (all HTTP/2 and HTTP/3 requests, and HTTP/1
  requests in absolute form), the URI's authority is updated to stay in sync
  with the new value. This update was performed using on of rotating trash
  chunk and could overwrite the new host value iteself, corrupting this way
  the request. The authority update is now performed in a dedicated buffer,
  so the forwarded request always remains consistent.

* http rules: Conditional "normalize-uri" rules could apply the wrong 
normalizer.

  When "percent-to-uppercase", "percent-decode-unreserved" or
  "path-strip-dotdot" was used without its optional argument and directly
  followed by an "if"/"unless" condition, the rule silently ended up as
  "path-merge-slashes". Such rules now perform the configured
  normalization. If you use them, be aware that URIs will now be rewritten
  as intended, while they were previously left mostly untouched. The issue
  was fixed by Youngkwang Lee.

* tcp rules: "tcp-request content" rules restarted from scratch on yield.

  A regression introduced in 3.2 made the evaluation of "tcp-request
  content" rules restart from the first rule each time a rule yielded more
  than once (for instance while waiting for more data), instead of resuming
  at the current one. Previous actions could then be re-executed. Evaluation
  now resumes at the waiting rule, avoiding these repeated actions.

* mux-h2/mux-spop: Two protocol handling issues were fixed.

  An H2 stream that only subscribed for sending without actually trying to
  send data was never woken up again. This could happen with health checks
  using the PROXY protocol on H2 connections when the handshake was not yet
  complete, leaving the check stuck until its timeout. These checks now
  resume correctly once the connection is ready.

  SPOE connections to agents were rejected when the HELLO frame arrived
  split across several TCP segments, because the frame header was parsed
  twice. HELLO and DISCONNECT frames are now correctly reassembled.

* task: A race in the destruction of shared tasks was fixed.

  Destroying a task that could still be scheduled by another thread could
  lead to the task being run after being freed, with a risk of crash.  Such
  tasks are now killed asynchronously instead, avoiding this race on
  multithreaded deployments.

* limits: Configuring "maxpipes" without "maxconn" could prevent startup.

  Setting "maxpipes" while leaving "maxconn" to be calculated automatically
  could make HAProxy refuse to start: the connection limit was calculated
  without reserving the file descriptors needed for the configured pipes,
  then rejected by the final resource checks. HAProxy now accounts for
  "maxpipes" when sizing the connection limit, allowing such configurations
  to start with a "maxconn" suited to the available file descriptors. There
  is no longer a need to set "maxconn" explicitly to work around this issue.

Other few minor issues were also addressed:

    * mux-h2: trailers received on a tunneled stream are now rejected.

    * TLS inspection: Bounds checks in the TLS ClientHello parser were fixed.

    * cache: An issue about possible hash collisions on the primary key was 
fixed.

    * http fetch: "http_auth_bearer" used with a custom header was fixes to
      work as expected in all cases

    * http analysis: The tunnel timeout was not applied on streasms with
      data filters, this was fixed. In addition, two issues with 1xx interim
      responses were fixed. The transaction status code after early hints is
      now properly restored to properly deal with internal responses, such
      as deny rules. And processing of 1xx interim responses in H2 was fixed
      to not truncate the final responses with no known length. Finally, the
      "http_fail_cnt" counter was wrongly incremented on error during
      response forwarding. Only actual server failures are now counted, once
      each.

    * log: CBOR-encoded integers and booleans could overflow the log buffer
      by one byte. This was fixed by reserving the trailing byte for the
      terminating-null byte. In addition, the "+json" log encoding now
      always produces valid JSON by escaping all bytes outside the printable
      range (for instance control characters or non-UTF-8 bytes).

    * debug: Crashes while dumping streams were fixed.

    * resolvers: Truncated DNS responses were misclassified. These responses
      are now classified correctly, making DNS failures easier to diagnose.

    * checks: HTTP health checks with several "host" headers could get
      corrupted because an outdated request-line could be used. It is now
      refreshed after each update.

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
   Q&A from devs    : https://github.com/orgs/haproxy/discussions
   Sources          : https://www.haproxy.org/download/3.2/src/
   Git repository   : https://git.haproxy.org/git/haproxy-3.2.git/
   Git Web browsing : https://git.haproxy.org/?p=haproxy-3.2.git
   Changelog        : https://www.haproxy.org/download/3.2/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 (8):
      BUG/MAJOR: h3: reject H3 truncated frames
      BUG/MEDIUM: h3: do not block FIN on empty DATA frame
      BUG/MINOR: h3: handle empty HEADERS frame as specified
      BUG/MINOR: h3: handle unknown frame type on request stream as specified
      BUG/MINOR: h3: only increment frame type counter on new header
      BUG/MEDIUM: mux_quic: do not free QCS if STOP_SENDING to sent
      BUG/MAJOR: mux_quic: fix leak on RESET_STREAM reception
      BUG/MEDIUM: mux_quic: activate timeout on FE init

Christopher Faulet (23):
      BUG/MEDIUM: mux-spop: Properly handle parsing of split HELLO/DISCONNECT 
frames
      BUG/MEDIUM: hlua: Never release a cosocket applet from the GC
      BUG/MINOR: mux-h1: Return an error on trailers if last chunk is unfinished
      BUG/MINOR: hlua: Always return nil if there is no data to dup for HTTP 
messages
      BUG/MEDIUM: cli: Don't read a command or payload line into a full buffer
      BUG/MEDIUM: htx: Reserve a block descriptor for zero-sized blocks
      CLEANUP: stream: Remove an excess newline in the stream dump
      BUG/MEDIUM: tcp-rules: Don't restart tcp-request content evaluation on 
yield
      BUG/MINOR: tools: Don't try to anonymize a NULL string
      BUG/MAJOR: htx: Check the header/trailer length limits when one is updated
      BUG/MINOR: http-client: Convert server timeout ticks when setting it
      BUG/MINOR: mux-h2: Don't expect more HTX data on 1xx interim responses
      BUG/MEDIUM: log: reserve the trailing 0 in CBOR int and bool encoders
      BUG/MEDIUM: http-htx: don't build the new authority in a rotating trash 
chunk
      BUG/MEDIUM: http-act: ignore "capture len" rules evaluated from a backend
      BUG/MEDIUM: tcp-rules: ignore "capture len" rules evaluated from a backend
      BUG/MINOR: http-ana: count response body failures only once in 
http_fail_cnt
      BUG/MINOR: http-fetch: http_auth_bearer() must not match a missing header
      BUG/MINOR: http-fetch: fix the space check of http_auth_bearer(<hdr>)
      BUG/MINOR: mux-h1: only mark C-L and T-E as sent once the header is 
emitted
      BUG/MINOR: tcpcheck: refresh the start-line after updating the authority
      BUG/MINOR: http-ana: restore the transaction status after early hints
      BUG/MINOR: mux-h2: Reject trailers received on a tunneled stream

Frederic Lecaille (11):
      BUG/MEDIUM: quic: crash on key update phase change after a failed one
      BUG/MINOR: quic: late packets of the first key phase are dropped
      MINOR: quic: protect the ChaCha20 header protection context from being 
freed
      BUG/MINOR: qpack: encoder and decoder stream data is never consumed
      BUG/MINOR: qpack: accept a Required Insert Count which cannot be reached
      BUG/MINOR: quic: delete the wrong CIDs when post-handshake frames fail
      BUG/MINOR: quic: leak of the NEW_TOKEN frame on token generation failure
      BUG/MEDIUM: map: do not overwrite the fetch context in pat_match_regm()
      REGTESTS: map: check map_regm inside an ACL over an iterating fetch
      BUG/MINOR: sample: reject a \0 byte in url_dec, json_query and jwt_*_query
      REGTESTS: http-rules: check "-m str" on a sample with an embedded \0

M9nx (1):
      BUG/MINOR: hlua: release private Lua rule data on teardown

Manu Nicolas (2):
      BUG/MINOR: resolvers: classify empty truncated responses
      BUG/MEDIUM: http-ana: apply tunnel timeout with data filters

Olivier Houchard (3):
      MEDIUM: mux-h1: Harden test for short data at end of stream
      BUG/MEDIUM: mux-h2: Make sure we remove H2_SF_NOTIFIED on subscribe
      BUG/MEDIUM: task: Do not destroy a task that is not ours in task_destroy

Remi Tricot-Le Breton (4):
      BUG/MINOR: cache: Manage collisions on primary key
      BUG/MINOR: cache: Seed cache primary hash
      BUG/MINOR: ssl: don't pass the address of a size_t as an int* to OpenSSL
      BUG/MINOR: ssl: Fix leak of ca_list in cafile_entry

William Lallemand (3):
      BUG/MINOR: payload: fix the cipher_len bound check in 
smp_client_hello_parse()
      BUG/MINOR: payload: bound ClientHello extension lists by the extension 
length
      BUG/MEDIUM: ssl: don't set a 0 timeout on an expired TLS session

Willy Tarreau (6):
      DOC: config: clarify tune tune.bufsize doc regarding various limits
      BUG/MINOR: stream/debug: harden the stream dump function regarding signals
      DOC: configuration: clarify the validity ranges of sample types
      BUG/MEDIUM: limits: properly account for global.maxpipes in 
compute_ideal_maxconn()
      BUG/MEDIUM: log: encode the whole non-printable range in the +json output
      REGTESTS: log: check the escaping performed by the +json option

Youngkwang Lee (1):
      BUG/MEDIUM: http_act: fix normalize-uri normalizer selection with a 
condition

--
Christopher Faulet



Reply via email to