From e98138a2c7c094a1cc120d749a57d1730abbd46d Mon Sep 17 00:00:00 2001 From: jholdstock Date: Fri, 17 Apr 2026 11:54:25 +0800 Subject: [PATCH] Don't block on channel send in oracle fee polling. Because this channel send occurs without a timeout or non-blocking select fallback, a delay in the consuming goroutine which synchronously transmits the fees to connected WebSocket clients will lock the Oracle's execution thread indefinitely. A remote attacker can exploit this architectural flaw by initiating slow or locked WebSocket connections (e.g. Slow Loris), effectively paralyzing the server's global fee rate calculations and resulting in a Denial of Service. As the ticker-driven background Oracle loop should never be subject to downstream consumer availability, the channel send must be refactored to be non-blocking. This allows the Oracle to drop a broadcast instance under severe load to prioritize system health rather than failing globally. --- dex/feerates/oracle.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dex/feerates/oracle.go b/dex/feerates/oracle.go index b97a2c7383..4cf80c9298 100644 --- a/dex/feerates/oracle.go +++ b/dex/feerates/oracle.go @@ -118,7 +118,11 @@ func (o *Oracle) calculateAverage() []int { // Notify all listeners if we have rates to broadcast. if len(broadCastFeeRates) > 0 { - o.listener <- broadCastFeeRates + select { + case o.listener <- broadCastFeeRates: + default: + // Listener channel is busy (or shutting down). Do not block the Oracle. + } } return reActivatedSourceIndexes