Skip to content

lightningd: accept OP_RETURN closer_scriptpubkey in simple-close check#9292

Merged
cdecker merged 1 commit into
ElementsProject:masterfrom
nGoline:fix/simpleclose-opreturn-force-close
Jul 8, 2026
Merged

lightningd: accept OP_RETURN closer_scriptpubkey in simple-close check#9292
cdecker merged 1 commit into
ElementsProject:masterfrom
nGoline:fix/simpleclose-opreturn-force-close

Conversation

@nGoline

@nGoline nGoline commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Under option_simple_close, a peer's closing_complete may set closer_scriptpubkey to a spec-valid OP_RETURN (BOLT2 permits it when the closer treats its output as uneconomical). closingd accepts and signs the closing tx, but master's close_tx_check validated every output against the two stored shutdown scripts only, so the OP_RETURN output matched neither, master rejected our own signed tx via channel_internal_error, and the channel force-closed.

This was remotely triggerable by any peer once the feature is negotiated.

The fix is to accept an output that is a valid, zero-value OP_RETURN, but only when option_simple_close is negotiated and only after the LOCAL-script match. Our own output is always paid to shutdown_scriptpubkey[LOCAL], so an OP_RETURN matching neither stored script can only be the peer's closer_scriptpubkey. Being unspendable and zero-value, accepting it preserves the check's anti-exfiltration property.
Kept master-side rather than whitelisting subd-reported negotiated scripts + validating in the signer since that would weaken the trusted-state check and require an HSM-protocol change affecting external signers (VLS).

Added lightningd/test/run-close_tx_check.c, which covers the accept path, feature-gating, non-zero-value rejection, and that unknown spendable scripts stay rejected. Verified to fail without the fix.

Reported by @0xaudron via the security process. option_simple_close is experimental (--experimental-simple-close, off by default) and unreleased, meaning no production exposure.

@nGoline nGoline added this to the v26.09 milestone Jul 7, 2026
@nGoline nGoline requested a review from cdecker July 7, 2026 16:50
A peer's closing_complete may set closer_scriptpubkey to a spec-valid
OP_RETURN, but close_tx_check only whitelisted the two stored shutdown
scripts, so master rejected our own signed tx and force-closed the
channel.  Accept a zero-value OP_RETURN output, only when
option_simple_close is negotiated.  Adds a regression test.

Reported-by: 0xaudron
Changelog-None: option_simple_close is experimental and unreleased.
@nGoline nGoline force-pushed the fix/simpleclose-opreturn-force-close branch from f69bac7 to c325683 Compare July 7, 2026 17:17

@cdecker cdecker left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK c325683

@cdecker cdecker enabled auto-merge (rebase) July 8, 2026 13:24
@cdecker cdecker merged commit 9b6a80f into ElementsProject:master Jul 8, 2026
87 of 89 checks passed
@nGoline nGoline deleted the fix/simpleclose-opreturn-force-close branch July 8, 2026 15:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants