AI-generated analysisPublished automatically and not human-verified. Validated context appears in community notes below.
← Watch feed
High 78 Bitcoin

Fix several on-the-fly-funding bugs (#3351)

Public commit record

What the developer wrote

Authored by Bastien Teinturier

98/100 · Strong
Fix several on-the-fly-funding bugs (#3351)

* Handle on-the-fly on-chain downstream failure post-restart

When restarting our node, we have a custom hook to avoid failing HTLCs
downstream when they're used with on-the-fly funding, because we want
to retry relaying those HTLCs. That doesn't apply to on-chain failures
though, because at that point the downstream channel has been closed.

* Don't relay on-the-fly HTLCs twice after restart

Before relaying on-the-fly HTLCs, we verify that they aren't already
being relayed. We only look at the pending changes, because once the
HTLCs are relayed we change their in-memory state in the Peer actor.

But if we restart after cross-signing on-the-fly HTLCs, we previously
would relay them again, thus paying the downstream user twice. We now
also look at the commitment transactions to avoid that.

* Force-close unpaid on-the-fly channels

When we fund an on-the-fly channel for which fees must be paid in the
follow-up HTLCs, our peer may act maliciously and ignore those HTLCs
when we relay them after funding the channel. We've already funded
the channel so it's too late to recover the on-chain fees we've paid,
so we previously just failed back the corresponding upstream HTLCs and
gave up on relaying them to the funded channel.

However, the HTLCs may already be cross-signed and pending on the funded
channel, which means that our peer could fulfill it and get paid while
we have failed the corresponding upstream HTLCs. In that case, we lose
funds. We can only fail the upstream HTLCs if we're sure that we haven't
relayed them yet,

Since obtaining this state is asynchronous and complex, we now opt-in to
a safer approach: we force-close the channel, check its commitments, and
only fail the upstream HTLCs that weren't relayed. If they have been
relayed, they will automatically be failed back when our HTLC-timeout
transaction confirms.

* Reject on-the-fly payment for batch of `payment_hashes`

While the protocol supports batching `payment_hashes`, we currently only
use it for one `payment_hash` at a time. It's thus safer to restrict it
to this to prevent potential abuse. We also explicitly reject the case
where an attacker tries to insert the same `payment_hash` twice to mess
up our state.

* Correctly relay preimages upstream after timeout

If we receive the preimage for an on-the-fly payment *after* the HTLC
has timed out, we still need to relay that preimage upstream, otherwise
we've paid downstream without being paid upstream.
✓ Descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode✓ Mentions testing or verification✓ Links an issue, advisory, or supporting reference
The short version

What changed, and why it matters

This commit fixes several bugs in Eclair's 'on-the-fly funding' feature, which lets a node open a Lightning channel and pay for it using future payment fees. The bugs could allow a malicious peer to make the node pay twice, lose money on force-closed channels, or fail to collect incoming payments after timeouts. The patch adds checks to prevent double-relaying payments, force-closes channels when fees are unpaid, and ensures preimages are still forwarded upstream even after an HTLC timeout.

Recommended action

Upgrade to a release containing this commit. Nodes using on-the-fly funding should be considered at risk of double-payment and loss-of-funds scenarios until patched. Monitor for any abnormal force-closures or duplicate HTLC relay attempts around the time of restart.

Security signals we found

01

Double-payment vulnerability fixed: paymentAlreadyRelayed now checks commitment transactions in addition to pending local changes, preventing relay of already-cross-signed HTLCs after restart.

02

Loss-of-funds vulnerability fixed: funded channels with unpaid future-HTLC fees are force-closed before upstream HTLCs are failed, avoiding a race where the peer fulfills a cross-signed downstream HTLC after we failed upstream.

03

Upstream settlement gap fixed: preimages received after HTLC expiry are now relayed upstream, preventing the node from paying downstream without being paid upstream.

04

Post-restart on-chain failure handling fixed: HtlcResult.OnChainFail now fails upstream instead of being suppressed for on-the-fly HTLCs.

05

Protocol abuse mitigated: batched payment_hashes and duplicate payment_hashes in on-the-fly funding requests are now rejected.

06

New actor introduced: ChannelCloserHtlcTimeout orchestrates CMD_FORCECLOSE and CMD_GET_CHANNEL_INFO to safely decide whether to fail upstream HTLCs.

07

Taproot witness parsing improved: extractPreimageFromClaimHtlcSuccess now handles taproot witnesses with an annex.

Risk score

Why this scored 78/100

Our methodology →
Potential impact 24/30
Exploitability 18/25
Stealth signal 12/15
Affected reach 10/15
Confidence 9/10
Evidence quality 5/5
Human-validated context

Community notes

Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.

No validated notes yet.

The AI analysis stands alone for now. Submit a note if you can add evidence or important context.