HTTPRequest::WriteReply() sends the reply body regardless of the request method, so a HEAD request is answered with the same body as the equivalent GET. RFC 9110 section 9.3.2 requires the HEAD response to carry the header section of the GET response (so Content-Length describes the body GET would have returned) but no body.
$ printf 'HEAD / HTTP/1.1\r\nHost: localhost\r\n\r\n' | nc 127.0.0.1 18443
HTTP/1.1 405 Method Not Allowed
Date: ...
Content-Length: 41
Content-Type: text/html; charset=ISO-8859-1
JSONRPC server handles only POST requests
A client that follows the specification stops reading after the header section, so the body bytes stay on the connection and are read as the start of the next response. On a direct connection this only confuses the client that sent the HEAD. With a reverse proxy that keeps upstream connections alive (for example nginx with proxy_http_version 1.1 and an upstream { keepalive N; } block) the stray bytes end up in the proxy's connection pool and corrupt the next response to whichever client is served from that connection. Both the 405 reply of the RPC endpoint and the REST endpoints answer HEAD without authentication, so a client that is merely allowed to connect can trigger it. The body is not attacker controlled, so this is a robustness issue rather than response injection.
This is not a regression from #35182: the libevent based server behaved the same way. evhttp_send_reply() writes the output buffer regardless of the method, and evhttp_response_needs_body() only suppresses the Content-Length and Content-Type headers for HEAD (so the old server sent the body without a Content-Length). The needs_body flag in WriteReply() was ported with that same role, which is why this PR leaves it alone and only drops the body: the header section stays identical to the GET response, as the RFC recommends.
The functional tests cover the RPC endpoint (405 path) and a REST endpoint (200 path). They send the HEAD request over a raw socket and read until the server goes quiet, checking that Content-Length equals the GET body length and that no bytes follow the header section. http.client cannot be used for this check because it silently discards a wrongly attached body.