rpcserver: use protocol max for fundMax, not maxChanSize
What changed, and why it matters
This fix corrects a bug in LND's OpenChannel RPC when the 'FundMax' option is used. Previously, the code wrongly used a configuration setting meant only for incoming channels (maxChanSize) as the upper limit for outgoing channels opened with FundMax. Now it uses the proper protocol-level maximum, which prevents users from accidentally being limited to a smaller channel size than the network actually allows. This is a correctness/availability issue rather than a direct theft-of-funds vulnerability, but it could cause unexpected channel-opening behavior or failed transactions.
Review whether any node operators relied on MaxChanSize to limit outgoing FundMax channels as an implicit policy control; if so, document or add an explicit outgoing limit. Otherwise, apply the patch and include it in the next release notes as a bug fix.
Security signals we found
Logic error: wrong constant used as upper bound for FundMax
Configuration option applied to outgoing flow contrary to documentation
Fix moves wumbo feature detection earlier and reuses it consistently
No input validation bypass or buffer overflow; issue is policy/correctness
Evidence from the diff
In rpcserver.parseOpenChannelReq, when in.FundMax was true, fundUpToMaxAmt was set to r.cfg.MaxChanSize. The commit changes this to use funding.MaxBtcFundingAmountWumbo if wumbo channels are enabled, otherwise MaxFundingAmount. It also moves the wumboEnabled check earlier so it can be reused. The non-FundMax path already enforced the correct protocol maximum. The bug caused FundMax to respect an admin-configured incoming-channel cap instead of the BOLT protocol cap.
Changed components
rpcserver.go parseOpenChannelReqOpenChannel RPC with FundMax flagInspect captured patch +15 / −9
diff --git a/rpcserver.go b/rpcserver.go
index 3d5c489..be4d056 100644
--- a/rpcserver.go
+++ b/rpcserver.go
@@ -2152,15 +2152,26 @@ func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest,
"the channel opening")
}
+ // Fetch our own feature set and determine wumbo support early, as it's
+ // needed for both FundMax and explicit amount validation.
+ globalFeatureSet := r.server.featureMgr.Get(feature.SetNodeAnn)
+ wumboEnabled := globalFeatureSet.HasFeature(
+ lnwire.WumboChannelsOptional,
+ )
+
// If the FundMax flag is set, ensure that the acceptable minimum local
// amount adheres to the amount to be pushed to the remote, and to
- // current rules, while also respecting the settings for the maximum
+ // current rules, while also respecting the protocol-level maximum
// channel size.
var minFundAmt, fundUpToMaxAmt btcutil.Amount
if in.FundMax {
- // We assume the configured maximum channel size to be the upper
- // bound of our "maxed" out funding attempt.
- fundUpToMaxAmt = btcutil.Amount(r.cfg.MaxChanSize)
+ // Use the protocol-level maximum as the upper bound for our
+ // funding attempt.
+ if wumboEnabled {
+ fundUpToMaxAmt = funding.MaxBtcFundingAmountWumbo
+ } else {
+ fundUpToMaxAmt = MaxFundingAmount
+ }
// Since the standard non-fundmax flow requires the minimum
// funding amount to be at least in the amount of the initial
@@ -2186,8 +2197,6 @@ func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest,
maxHtlcs := uint16(in.RemoteMaxHtlcs)
remoteChanReserve := btcutil.Amount(in.RemoteChanReserveSat)
- globalFeatureSet := r.server.featureMgr.Get(feature.SetNodeAnn)
-
// Determine if the user provided channel fees
// and if so pass them on to the funding workflow.
var channelBaseFee, channelFeeRate *uint64
@@ -2212,9 +2221,6 @@ func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest,
// in the wallet hence we do not check it here against the maximum
// funding amount. Only if the localFundingAmt is specified we can check
// if it exceeds the maximum funding amount.
- wumboEnabled := globalFeatureSet.HasFeature(
- lnwire.WumboChannelsOptional,
- )
if !in.FundMax && !wumboEnabled && localFundingAmt > MaxFundingAmount {
return nil, fmt.Errorf("funding amount is too large, the max "+
"channel size is: %v", MaxFundingAmount)
Why this scored 40/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.