ln: use outer onion values in PendingHTLCInfo for trampoline
What changed, and why it matters
This commit fixes a bug in how trampoline routing nodes validate incoming Lightning payments. Previously, the node used values from the inner (trampoline) onion, which included the fee budget, to check whether it received the correct amount. A malicious or buggy upstream node could forward less money than intended, and as long as the shortfall stayed within the fee budget, the trampoline node would not detect it. The patch makes the node use the outer onion's stated amount instead, so it can verify it actually received what it was supposed to before forwarding.
Treat as a security fix and include in release notes. Users running trampoline routing nodes should upgrade. Review related follow-up commit for complete trampoline routing-info tracking. Consider whether the blinded-forward check's discarded return values need additional validation elsewhere.
Security signals we found
Use of incorrect payment amount source for validation (inner vs outer onion)
Potential fee-budget underpayment by upstream peer
Fix changes which amount value is stored in pending HTLC state for trampoline forwarding
Commit message explicitly describes the security/fee-skimming risk
Evidence from the diff
In lightning/src/ln/onion_payment.rs, create_fwd_pending_htlc_info now populates PendingHTLCInfo with outer_hop_data.amt_to_forward and outer_hop_data.outgoing_cltv_value rather than next_trampoline_hop_data.amt_to_forward / outgoing_cltv_value or the blinded-forward-calculated values. The outer onion values represent the amount and expiry the previous peer committed to forwarding to this node. Using the inner trampoline onion values (which include the node’s fee budget) allowed an upstream peer to underpay the trampoline node within that budget without detection. The blinded-forward check result is now intentionally discarded with _next_hop_amount / _next_hop_cltv, indicating a follow-up commit will add separate trampoline routing tracking.
Changed components
lightning/src/ln/onion_payment.rsTrampoline payment forwarding logicPendingHTLCInfo constructionInspect captured patch +5 / −5
diff --git a/lightning/src/ln/onion_payment.rs b/lightning/src/ln/onion_payment.rs
index 4fe44ac..df32d50 100644
--- a/lightning/src/ln/onion_payment.rs
+++ b/lightning/src/ln/onion_payment.rs
@@ -178,8 +178,8 @@ pub(super) fn create_fwd_pending_htlc_info(
current_path_key: None,
incoming_multipath_data: outer_hop_data.multipath_trampoline_data,
},
- next_trampoline_hop_data.amt_to_forward,
- next_trampoline_hop_data.outgoing_cltv_value,
+ outer_hop_data.amt_to_forward,
+ outer_hop_data.outgoing_cltv_value,
None,
None
)
@@ -189,7 +189,7 @@ pub(super) fn create_fwd_pending_htlc_info(
// amount that the trampoline node will forward onward, not the individual amount that
// arrives in a single (incoming MPP) HTLC. We used the desired total amount to
// calculate our outbound values.
- let (amt_to_forward, outgoing_cltv_value) = check_blinded_forward(
+ let (_next_hop_amount, _next_hop_cltv) = check_blinded_forward(
outer_hop_data.multipath_trampoline_data.as_ref().map(|f| f.total_msat).unwrap_or(msg.amount_msat), msg.cltv_expiry, &next_trampoline_hop_data.payment_relay, &next_trampoline_hop_data.payment_constraints, &next_trampoline_hop_data.features
).map_err(|()| {
// We should be returning malformed here if `msg.blinding_point` is set, but this is
@@ -209,8 +209,8 @@ pub(super) fn create_fwd_pending_htlc_info(
current_path_key: outer_hop_data.current_path_key,
incoming_multipath_data: outer_hop_data.multipath_trampoline_data,
},
- amt_to_forward,
- outgoing_cltv_value,
+ outer_hop_data.amt_to_forward,
+ outer_hop_data.outgoing_cltv_value,
next_trampoline_hop_data.intro_node_blinding_point,
next_trampoline_hop_data.next_blinding_override
)
Why this scored 59/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.