From e4c4e116274ff393b38493903a19d2650e002f37 Mon Sep 17 00:00:00 2001 From: Slyghtning Date: Mon, 11 May 2026 15:22:05 +0200 Subject: [PATCH] loopd: nil-guard reservation/instant-out RPC handlers When loopd is started without --experimental the swap client server's reservationManager and instantOutManager are nil. ListReservations already returns codes.Unimplemented in that case; the rest of the instant-out / reservation RPC family didn't, and would dereference a nil pointer. Affected handlers (all of which now return the same Unimplemented status): - ReservationRequest (new in PR #883) - ReservationQuote (new in PR #883) - InstantOut - InstantOutQuote - ListInstantOuts Without this fix an authenticated caller can crash the daemon by invoking any of these RPCs against a non-experimental loopd. With default localhost binding the attack surface is small, but loop is also commonly fronted by lit / LSP wrappers that expose RPCs to other internal services, so a single packet is enough for a remote DoS. --- loopd/swapclient_server.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/loopd/swapclient_server.go b/loopd/swapclient_server.go index 8bef9d1f..81d72f2a 100644 --- a/loopd/swapclient_server.go +++ b/loopd/swapclient_server.go @@ -1743,6 +1743,11 @@ func (s *swapClientServer) ReservationRequest(ctx context.Context, req *looprpc.ReservationRequestRequest) ( *looprpc.ReservationRequestResponse, error) { + if s.reservationManager == nil { + return nil, status.Error(codes.Unimplemented, + "Restart loop with --experimental") + } + reservation, err := s.reservationManager.RequestReservationFromServer( ctx, btcutil.Amount(req.Amt), req.Expiry, btcutil.Amount(req.MaxPrepayAmt), @@ -1755,10 +1760,16 @@ func (s *swapClientServer) ReservationRequest(ctx context.Context, Reservation: toClientReservation(reservation), }, nil } + func (s *swapClientServer) ReservationQuote(ctx context.Context, req *looprpc.ReservationQuoteRequest) ( *looprpc.ReservationQuoteResponse, error) { + if s.reservationManager == nil { + return nil, status.Error(codes.Unimplemented, + "Restart loop with --experimental") + } + quote, err := s.reservationManager.QuoteReservation( ctx, btcutil.Amount(req.Amt), req.Expiry, )