trampoline: prevent adding ourself on the route
What changed, and why it matters
This commit fixes a bug in Electrum's Lightning trampoline routing where a payer could accidentally include themselves as a hop on the payment route. When a user had a direct channel with the recipient, their own public key could appear in the invoice's trampoline list, and the routing code would then try to route the payment through themselves. This caused legitimate payments to fail. The fix simply removes the user's own public key from the list of candidate trampoline hops before building the route.
No immediate security response required. This is a bug fix that prevents routing failures in trampoline payments when payer and payee share a direct channel. Users running Lightning trampoline payments should update to include this fix, especially if experiencing payment failures after PR #10541.
Security signals we found
Self-inclusion in payment route could cause payment failure (denial-of-service to own payment)
Lightning routing logic bug in trampoline payments
No evidence of malicious exploitation path in the diff
Fix is a defensive guard clause with minimal code change
Evidence from the diff
In electrum/trampoline.py, create_trampoline_route() now calls invoice_trampolines.discard(my_pubkey) before constructing the trampoline route. This prevents a node from adding itself as a trampoline hop when it is connected directly to the payee and the payee’s invoice includes it as a trampoline. The change is a follow-up to PR #10541, which caused a regtest node (Bob) to signal trampoline support and include Alice in the invoice trampoline; Alice would then attempt to route through herself, failing the payment. The patch is defensive and partial in that it addresses one specific self-inclusion scenario.
Changed components
electrum/trampoline.pycreate_trampoline_route()Lightning trampoline payment routingInspect captured patch +2 / −0
diff --git a/electrum/trampoline.py b/electrum/trampoline.py
index 78f13c5..1df250b 100644
--- a/electrum/trampoline.py
+++ b/electrum/trampoline.py
@@ -224,6 +224,8 @@ def create_trampoline_route(
) -> LNPaymentTRoute:
# we decide whether to convert to a legacy payment
is_legacy, invoice_trampolines = is_legacy_relay(invoice_features, r_tags)
+ # we can be in the invoice_trampolines e.g. if we have a direct channel with the recipient
+ invoice_trampolines.discard(my_pubkey)
_logger.debug(f"Creating trampoline route for invoice_pubkey={invoice_pubkey.hex()}, {is_legacy=}")
# we build a route of trampoline hops and extend the route list in place
Why this scored 33/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.