lightningd: remove withheld flag when we see sendpsbt.
What changed, and why it matters
This change fixes a bookkeeping bug in Core Lightning's wallet code. When a user calls the `sendpsbt` RPC to broadcast a funding transaction, the code now clears an internal 'withheld' flag on the relevant channel. Previously, this flag could remain stuck, which might prevent the channel from advancing normally after the PSBT (partially-signed Bitcoin transaction) was sent. The patch is small and only adjusts internal state tracking; it does not appear to introduce a direct remote exploit.
Apply the patch. It is a low-risk state-cleanup fix. If running a node that uses PSBT-based funding (especially dual-funded or RBF channels), ensure the node is updated so that channels do not remain stuck in a withheld state after `sendpsbt` is called. No immediate emergency response is warranted based on the diff alone.
Security signals we found
State-machine inconsistency: a channel flag was not cleared after the corresponding action (sending PSBT) was performed
Potential denial-of-service or stuck channel state due to stale flag
No input validation or memory-safety bug visible in the diff
Evidence from the diff
In wallet/walletrpc.c, the json_sendpsbt handler iterates over channels whose funding_psbt matches the PSBT being sent. The patch adds a local was_withheld variable, records the previous value of c->withheld, sets c->withheld = false, and logs whether the channel was previously withheld. The withheld flag is used elsewhere in Core Lightning to mark channels whose funding transaction should not yet be broadcast (for example, during dual-funding or RBF flows). Forgetting to clear it when sendpsbt is called could leave the channel in a state where subsequent logic still treats it as unbroadcastable, causing hangs or failed state transitions. The change is defensive and corrects state consistency.
Changed components
wallet/walletrpc.cjson_sendpsbt RPC handlerchannel funding state machinewithheld flag logicInspect captured patch +6 / −1
diff --git a/wallet/walletrpc.c b/wallet/walletrpc.c
index 31b5075..92f979a 100644
--- a/wallet/walletrpc.c
+++ b/wallet/walletrpc.c
@@ -1199,6 +1199,8 @@ static struct command_result *json_sendpsbt(struct command *cmd,
struct channel *c;
list_for_each(&p->channels, c, list) {
+ bool was_withheld;
+
if (!c->funding_psbt)
continue;
if (psbt_is_finalized(c->funding_psbt))
@@ -1209,9 +1211,12 @@ static struct command_result *json_sendpsbt(struct command *cmd,
/* Found one! */
tal_free(c->funding_psbt);
c->funding_psbt = clone_psbt(c, sending->psbt);
+ was_withheld = c->withheld;
+ c->withheld = false;
wallet_channel_save(ld->wallet, c);
log_info(c->log,
- "Funding PSBT sent, and stored for rexmit");
+ "Funding PSBT sent, and stored for rexmit%s",
+ was_withheld ? " (was withheld)" : "");
}
}
Why this scored 41/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.