A relay client could send data with no end-of-line (an unterminated method
or header line) and dribble its payload, making WeeChat accumulate it in the
partial message buffer that grew without limit, until all memory was
exhausted. This path is reachable before authentication during websocket
initialization with the "weechat" and "irc" protocols.
The accumulated partial message is now bounded by
RELAY_HTTP_PARTIAL_MESSAGE_MAX_LENGTH: once the limit is reached, the extra
data is ignored.
A relay client could announce a huge websocket frame (or HTTP body via
"Content-Length") and dribble its payload, making WeeChat accumulate it
in a buffer that grew without limit, until all memory was exhausted. The
websocket frame path is reachable before authentication with the
"weechat" and "irc" protocols.
The announced websocket frame length and HTTP "Content-Length" are now
bounded by WEBSOCKET_FRAME_MAX_LENGTH and RELAY_HTTP_BODY_MAX_LENGTH: an
oversized websocket frame closes the connection, and an oversized body is
rejected.
A malicious or compromised IRC server could send data with no end-of-line
(or a flood of "005" messages), making WeeChat accumulate it in a buffer
that grew without limit, until all memory was exhausted.
The unterminated received message and the accumulated "005" (ISUPPORT)
data are now bounded by IRC_SERVER_RECV_MSG_MAX_LENGTH and
IRC_SERVER_ISUPPORT_MAX_LENGTH: extra data is ignored once the limit is
reached.
weecrypto_totp_validate compared the generated and client-supplied OTPs
with strcmp and broke out of the time-window loop on the first match.
Both choices leaked information via response timing: strcmp leaked the
expected OTP digit-by-digit (shrinking the brute-force search from
~10^digits to a handful of guesses within the 30-second window), and
the early break leaked which window offset matched.
Compare in constant time with string_memcmp_constant_time and always
iterate the full window, OR-ing the result into otp_ok without an
early exit.
This affects both relay protocols (which call totp_validate via the
public info hook) and any other caller of the info hook.
The IRC relay protocol's PASS handler compared the server password with
the client-supplied value using strcmp, leaking the password byte-by-byte
via response timing. This is the same class of bug fixed for the api and
weechat protocols, on a separate code path that did not go through
relay_auth_check_password_plain.
Extract the HMAC-then-constant-time-compare logic from
relay_auth_check_password_plain into relay_auth_password_equals, then
use it in both the plain-auth wrapper and the IRC PASS handler.
The relay authentication used non-constant-time comparisons (strcasecmp,
strcmp) to verify password hashes and plaintext passwords, allowing an
attacker to derive the expected hash byte-by-byte from response timing
and then authenticate without knowing the password.
- SHA/PBKDF2 hex hash comparisons: normalize the client-supplied hash to
uppercase and compare in constant time over the fixed expected length.
- Plaintext password comparison: HMAC-SHA256 both passwords with a fresh
per-call random key and compare the fixed-size MACs in constant time,
hiding both per-byte timing and the password length.
Add string_memcmp_constant_time helper in core, exposed via the plugin
API. Bump WEECHAT_PLUGIN_API_VERSION accordingly.
An authenticated relay client using the permessage-deflate websocket
extension could send a small compressed frame that decompresses to an
unbounded amount of data, exhausting all memory and crashing WeeChat.
The output buffer in relay_websocket_inflate is now capped to
WEBSOCKET_INFLATE_MAX_SIZE: frames decompressing beyond this limit are
rejected and the connection is closed.