monad-wireauth: split handshake rate limits by cookie validity#2778
monad-wireauth: split handshake rate limits by cookie validity#2778
Conversation
318a3b0 to
78051fc
Compare
78051fc to
8e90e1f
Compare
There was a problem hiding this comment.
Pull request overview
This PR addresses a security vulnerability in the handshake rate limiting mechanism by splitting the global handshake budget into two independent rate limits based on cookie validity. Previously, an attacker could exhaust the single global handshake budget while keeping total_sessions below the low watermark, effectively preventing legitimate new connections without triggering cookie-based protections.
Changes:
- Split handshake rate limit into separate budgets for cookie-verified and cookie-unverified handshake initiations
- When unverified budget is exhausted, send cookie replies (if verified budget permits) instead of silently dropping, allowing honest peers to obtain cookies
- When both budgets are exhausted, drop requests to prevent amplification attacks
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| monad-wireauth/src/config/mod.rs | Replaced single handshake_rate_limit field with handshake_cookie_unverified_rate_limit and handshake_cookie_verified_rate_limit; removed unused max_requests_per_ip field |
| monad-wireauth/src/filter.rs | Implemented dual counter system with separate logic for verified/unverified budgets; counters are checked before watermark checks to prevent the attack |
| monad-wireauth/src/api.rs | Updated Filter::new() call to pass both rate limit parameters |
| monad-wireauth/tests/tests.rs | Updated tests to use new config fields and verify new behavior (4 packets including cookie reply instead of 2 drops) |
| monad-wireauth/README.md | Updated documentation to reflect new rate limits and removed deprecated max_requests_per_ip parameter |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| } | ||
| self.cookie_verified_counter += 1; | ||
| } else { | ||
| if self.cookie_unverified_counter >= self.handshake_cookie_unverified_rate_limit { |
There was a problem hiding this comment.
Doesn't this reveal some of the internal state?
There are three observable outcomes, namely
- a handshake reply
- a cookie
- nothing, packet gets dropped
As an adversary, we can
- sample a random cookie
- use a previously retrieved cookie
To see if the node is busy, we send a random value. If the node replies with a cookie, we know that usage is very low and take the cookie. Otherwise, we use a correct cookie. If the packet gets dropped and we don't receive a reply, then usage has execeeded self.handshake_cookie_verified_rate_limit. If we receive a reply with the handshake reply, we know that usage is below self.handshake_cookie_verified_rate_limit
There was a problem hiding this comment.
do you see a specific problem? this should not be an important factor in preventing exploit that i am trying to mitigate
cookie can be used to rate limit by ip, so to consume whole verified budget someone will need to get ips to bypass that rate limit. with default params that would be 10_000 ips
There was a problem hiding this comment.
True, it does not affect the mitigation of the vulnerability but it might create a new side channel that leaks useful data for DoS attacks.
8e90e1f to
4a3ab6e
Compare
right now the "cookie/ip validation" path only kicks in once total_sessions >= low_watermark_sessions. an attacker can try to keep total_sessions just below that threshold while still generating enough handshake traffic to consume the global handshake budget, causing honest peers' new connections to get delayed or dropped without ever triggering cookie-gated, per-ip controls. split the handshake budget into two independent rate limits: - handshake_cookie_unverified_rate_limit for cookie-invalid initiations - handshake_cookie_verified_rate_limit for cookie-valid initiations this decouples abuse protection from session count watermarks: even if the attacker keeps sessions below low_watermark_sessions, cookie-invalid floods cannot starve the cookie-verified budget. each class still has a hard cap per reset interval to protect the node under extreme load.
4a3ab6e to
aabae39
Compare
|
right now the "cookie/ip validation" path only kicks in once
total_sessions >= low_watermark_sessions. an attacker can try to keep
total_sessions just below that threshold while still generating enough
handshake traffic to consume the global handshake budget, causing honest
peers new connections to get delayed or dropped without ever triggering
cookie-gated, per-ip controls.
split the handshake budget into two independent rate limits:
once the cookie-unverified budget is exhausted we send cookie replies
instead of dropping, so honest peers can obtain a cookie and retry into
the protected verified lane. cookie replies are smaller than initiation/response,
so even if we reply under attack we are not amplifying traffic
closes: #2777