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

channeld: split the feerate we'll pay from the one we'll accept

Public commit record

What the developer wrote

Authored by cdecker

85/100 · Strong
channeld: split the feerate we'll pay from the one we'll accept

The previous commit clamped our own fee source on the way in. This is
the counterpart for the other side of the channel: our peer's estimator
can be just as broken as ours, and we are the only one in a position to
notice before their money is gone.

`splice_accepter` only rejected a remote `funding_feerate_perkw` below
feerate_min; there was no upper bound at all. The downstream safeguard
in check_balances only inspects the accepter's own fee contribution, and
since accepter_relative is 0 our weight is nil, so that check never
fires. A peer whose estimator has gone haywire can therefore drive a
splice at an arbitrary feerate and we will cheerfully sign it, even
though the fee comes out of their channel balance. Refusing costs us
nothing and saves them from committing their funds to a transaction they
did not mean to pay for.

Reject anything above feerate_max, and apply the same bound in
handle_splice_init so that we extend the same courtesy in reverse: if
our own estimator is the broken one, we catch it before we ask a peer to
sign for it. handle_splice_init honours `splice_force_feerate` there,
as check_balances already does: that flag is the user saying they meant
it, and a policy limit should not override it.

feerate_max also needs a bound of its own, since it was derived purely
from the estimates times config.max_fee_multiplier. But a single bound
cannot serve both directions, because feerate_max gates what we accept
in `update_fee` *and* what we propose ourselves. Set for the accept
side it would have us paying absurd fees; set for the propose side it
would pin our commitment feerate below what a congested chain demands,
which is precisely when it has to confirm. So there are now two:

- FEERATE_CEILING (1000000 perkw, 4000 sat/vB) is the most we let a
peer drive us to. Their estimator being broken is not by itself
worth dropping a channel over, so this only has to exclude the
absurd.
- MAX_OUR_FEERATE_PER_KW (100000 perkw, 400 sat/vB) is the most we will
pay: roughly 0.011 BTC for a bare anchor commitment. Declining to
propose a feerate costs us nothing, so we can afford to be strict.
our_feerate_max() applies it wherever the money is ours:
default_feerate, splice_feerate, opening_feerate and dual-fund RBF.

Note this leaves the paths where we cannot decline -- mutual close,
penalty and onchain resolution -- bounded only by the ceiling, which is
the right answer for a feerate that has a deadline attached.

channeld needs both, so channeld_init and channeld_feerates carry
our_feerate_max alongside feerate_max, and check_balances holds whichever
side is ours to the stricter one. The multiplier is settable via
--dev-max-fee-multiplier, so widen to u64 before multiplying.

Finally, remove the UINT_MAX sentinels. feerate_max returned UINT_MAX
when there were no estimates at all, and lightningd overwrote the bound
with 0xFFFFFFFF when fee limits were ignored. Both are the bound a
peer's proposal is measured against, and we store what we accept -- a
u32 that large overflows the 25/24 RBF calculation downstream. The
unknown path now falls back to FEERATE_CEILING, exactly as feerate_min
falls back to FEERATE_FLOOR, and ignore_fee_limits travels to channeld
and openingd as an explicit flag which relaxes the policy bounds but
never the ceiling. That last part makes a documented promise false, so
the three places which say ignore-fee-limits means "any fee they want"
now say what it actually means.

Changelog-Fixed: channeld: a peer can no longer initiate a splice at an arbitrarily high feerate; it is now bounded like other remote-proposed feerates.
Changelog-Changed: lightningd: we no longer propose a feerate above 100000perkw (400 sat/vB) of our own accord, for channel opens, splices, commitment updates and dual-fund RBFs.
Changelog-Changed: lightningd: `--ignore-fee-limits` and `setchannel`'s `ignorefeelimits` still drop our policy bounds, but no longer accept a feerate above 1000000perkw (4000 sat/vB).
Changelog-Changed: JSON-RPC: `feerates` reports `max_acceptable` as the feerate ceiling rather than 4294967295 when no fee estimates are available.
(cherry picked from commit 4a10d71822c277e381bf289202f494e64110b522)
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode
The short version

What changed, and why it matters

This commit fixes a bug in Core Lightning where a channel peer could trick or accidentally push the node into signing a Bitcoin transaction with an absurdly high transaction fee during a 'splice' operation. Before the fix, there was no upper limit on the fee rate a peer could propose for a splice, and an internal balance check did not catch it because the accepting side contributed no funds. The patch adds two separate fee ceilings: a sanity ceiling on what any peer can propose, and a stricter self-imposed limit on fees the node itself will pay for its own transactions. It also removes unsafe 'no limit' sentinel values that could overflow later calculations.

Recommended action

Treat this as a security fix and include it in the next maintenance release. Operators running nodes that accept inbound channel opens or splice requests should upgrade, especially if they use default fee settings. Review any custom max_fee_multiplier values, as the patch now clamps the result to FEERATE_CEILING. No immediate on-chain action is required.

Security signals we found

01

Fixes missing upper bound on remote-proposed splice feerate

02

Adds explicit sanity ceiling (FEERATE_CEILING) and stricter self-payment cap (MAX_OUR_FEERATE_PER_KW)

03

Removes UINT_MAX sentinel that could overflow 25/24 RBF calculation

04

Propagates ignore_fee_limits as explicit boolean instead of overwriting bounds with 0xFFFFFFFF

05

Holds own side of splice to stricter limit in check_balances

06

Applies force_feerate override only to policy limit, not safety ceiling

07

Updates documentation to correct prior 'any fee they want' claim

Risk score

Why this scored 72/100

Our methodology →
Potential impact 22/30
Exploitability 14/25
Stealth signal 10/15
Affected reach 12/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.