splice: Sign shared output early
What changed, and why it matters
This change adjusts how Core Lightning handles 'splicing' (a way to resize a Lightning channel's on-chain funding). When a user splices multiple channels at the same time, the software now signs a shared piece of the transaction earlier than before, so it can build a complete signatures message for all peers. The commit describes this as fixing a deadlock, not as a security vulnerability. There is no direct evidence in the commit or supplied references that this is exploitable by an attacker.
Treat as a normal functional/protocol fix. Review the splice state machine to confirm the pre-signed signature cannot be extracted or replayed by a peer before the intended protocol step, and ensure the HSM only signs splice transactions it has validated. No emergency action is indicated by the available evidence.
Security signals we found
Change touches channel funding/signature logic
HSM signing call added for splice transaction
Commit message frames change as protocol deadlock fix, not security bug
No explicit bounds checks or input validation changes visible
No disclosed CVE, advisory, or researcher attribution in commit
Evidence from the diff
In channeld/channeld.c, splice_initiator_user_finalized() now pre-signs the splice funding (shared) output before adding the in-flight splice. It builds the current splice transaction from the PSBT, asks the HSM to sign it via towire_hsmd_sign_splice_tx, and stores the resulting signature in the PSBT input. The stated reason is to allow construction of a complete tx_signatures message when two or more channels share outputs in a multi-channel splice, breaking a circular dependency/deadlock. The signature is still produced by the HSM and stored locally; it is not sent to the peer until later in the protocol.
Changed components
channeld/channeld.cLightning splice protocol handlingHSM splice transaction signing interfaceInspect captured patch +41 / −0
diff --git a/channeld/channeld.c b/channeld/channeld.c
index 43914b6..d50e81b 100644
--- a/channeld/channeld.c
+++ b/channeld/channeld.c
@@ -4277,6 +4277,8 @@ static void splice_initiator_user_finalized(struct peer *peer)
u8 *outmsg;
struct interactivetx_context *ictx;
struct bitcoin_tx *prev_tx;
+ struct bitcoin_tx *bitcoin_tx;
+ struct bitcoin_signature splice_sig;
bool sign_first;
char *error;
u32 chan_output_index, splice_funding_index;
@@ -4288,6 +4290,7 @@ static void splice_initiator_user_finalized(struct peer *peer)
struct amount_msat current_push_val;
const enum tx_role our_role = TX_INITIATOR;
u8 *abort_msg;
+ const u8* msg;
/* We must loading the funding tx as our previous utxo */
prev_tx = bitcoin_tx_from_txid(peer, peer->channel->funding.txid);
@@ -4336,6 +4339,44 @@ static void splice_initiator_user_finalized(struct peer *peer)
psbt_elements_normalize_fees(ictx->current_psbt);
+ /* We have to sign the shared output early (here) for cases where we are
+ * splicing between multiple channels simultaneously. This is so the
+ * we can build a complete `tx_signatures` message when there are two
+ * or more shared outputs between mulitple peers */
+
+ splice_sig.sighash_type = SIGHASH_ALL;
+
+ bitcoin_tx = bitcoin_tx_with_psbt(tmpctx, ictx->current_psbt);
+
+ status_info("Splice pre-signing tx: %s",
+ tal_hex(tmpctx, linearize_tx(tmpctx, bitcoin_tx)));
+
+ msg = towire_hsmd_sign_splice_tx(tmpctx, bitcoin_tx,
+ &peer->channel->funding_pubkey[REMOTE],
+ splice_funding_index);
+
+ msg = hsm_req(tmpctx, take(msg));
+ if (!fromwire_hsmd_sign_tx_reply(msg, &splice_sig))
+ status_failed(STATUS_FAIL_HSM_IO,
+ "Reading sign_splice_tx reply: %s",
+ tal_hex(tmpctx, msg));
+
+ /* Set the splice_sig on the splice funding tx psbt */
+ if (!psbt_input_set_signature(ictx->current_psbt, splice_funding_index,
+ &peer->channel->funding_pubkey[LOCAL],
+ &splice_sig))
+ status_failed(STATUS_FAIL_INTERNAL_ERROR,
+ "Unable to pre-set signature internally "
+ "funding_index: %d "
+ "my pubkey: %s "
+ "my signature: %s "
+ "psbt: %s",
+ splice_funding_index,
+ fmt_pubkey(tmpctx,
+ &peer->channel->funding_pubkey[LOCAL]),
+ fmt_bitcoin_signature(tmpctx, &splice_sig),
+ fmt_wally_psbt(tmpctx, ictx->current_psbt));
+
status_debug("Splice adding inflight: %s",
fmt_wally_psbt(tmpctx, ictx->current_psbt));
Why this scored 31/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.