The MPP timeout logic in timer_tick_occurred (channelmanager.rs:8881) is gated behind if let OnionPayload::Invoice { .. }, so keysend payments (OnionPayload::Spontaneous) skip it entirely. Incomplete keysend MPP parts stay in claimable_payments until CLTV expiry instead of timing out after MPP_TIMEOUT_TICKS.
This lets an attacker hold HTLC slots for the full CLTV delta (e.g. ~24 hours) instead of ~3 minutes by sending partial keysend MPP HTLCs. Bounded by per-channel HTLC limits and eventual CLTV cleanup, so it's a resource exhaustion vector, not funds loss.
I confirmed this with a targeted runtime repro: after advancing timer_tick_occurred for MPP_TIMEOUT_TICKS, the partial keysend MPP was still pending, and delivering the second half afterward successfully completed the payment.
Fix: remove the OnionPayload::Invoice guard so the timeout applies to all incomplete MPP payments.
The MPP timeout logic in
timer_tick_occurred(channelmanager.rs:8881) is gated behindif let OnionPayload::Invoice { .. }, so keysend payments (OnionPayload::Spontaneous) skip it entirely. Incomplete keysend MPP parts stay inclaimable_paymentsuntil CLTV expiry instead of timing out afterMPP_TIMEOUT_TICKS.This lets an attacker hold HTLC slots for the full CLTV delta (e.g. ~24 hours) instead of ~3 minutes by sending partial keysend MPP HTLCs. Bounded by per-channel HTLC limits and eventual CLTV cleanup, so it's a resource exhaustion vector, not funds loss.
I confirmed this with a targeted runtime repro: after advancing
timer_tick_occurredforMPP_TIMEOUT_TICKS, the partial keysend MPP was still pending, and delivering the second half afterward successfully completed the payment.Fix: remove the
OnionPayload::Invoiceguard so the timeout applies to all incomplete MPP payments.