Every captured commit receives deterministic security triage and a separate communication-quality score. Security candidates and broader second-pass signals receive full-patch Ollama analysis.
Message quality measures whether a commit identifies its scope, purpose, rationale, testing, and supporting references. It does not change the security-severity score.
This commit changes how the Lightning networking code handles oversized encrypted messages. Previously, certain conditions would cause the program to crash with a panic. Now the code returns errors instead, which is a defensive improvement…
panic-to-error conversion for oversized message encryption/decryptiondenial-of-service hardening against oversized peer messagesdebug_assert retained to preserve test coverage of invariant violations
This patch fixes a crash bug in the Lightning Dev Kit's handling of HTLC failure messages. A downstream peer could send a maximally-sized failure message without attribution data. When the node added its own attribution data while relaying…
Denial-of-service via remote-triggered panic in message encryptionOversized message exceeding Noise/Lightning wire framing limitMissing length validation before adding attribution data during relay
This commit fixes a denial-of-service bug in rust-lightning where a maliciously crafted one-hop blinded reply path could cause the node to panic when it tried to respond. The fix rejects paths with too few hops before advancing them, and a…
Denial-of-service vector via malformed blinded pathPanic in onion construction due to zero-hop pathUntrusted reply path input validation gap
This commit fixes a bug where replaying the current blockchain block through a normal listener callback could crash two core Lightning components (ChannelManager and OutputSweeper) with a panic. The fix recognizes a same-block replay as a …
panic in chain listener callbacksame-block replay/rescan mishandlingassertion failure on valid chain input
This commit fixes a crash bug in the Lightning Dev Kit's on-chain transaction handler. During a deep blockchain reorganization, a previously settled HTLC claim could be 'resurrected' at a block height where it could no longer be combined w…
Assertion/panic in reorg handling pathDeep blockchain reorg as trigger conditionHTLC claim resurrection after reorg
This commit simply updates the 'repository' web links in 15 package metadata files from GitHub to a self-hosted Forgejo instance. It does not change any program code, build logic, dependencies, or security behavior. There is no security is…
This commit fixes a bug in the Lightning Dev Kit where, after a disconnection, a node could fail to retransmit a 'splice_locked' message to a peer that was still waiting for transaction signatures. Without this retransmission, the two peer…
Protocol state desynchronization between channel peers after reconnectionMissing retransmission of splice_locked for 0-conf splice channelsPotential channel unusability or stuck splice negotiation
This commit fixes a small accounting bug in how the Lightning wallet estimates the size (and therefore transaction fee) of a special Bitcoin transaction that sweeps funds back to the user after a channel closes. The old code always assumed…
debug assertion failure possible in development/testing buildstransaction weight/fee estimate overestimation up to 3 WUconstant replaced with per-descriptor length computation
This commit only updates documentation comments for a Rust function called get_per_commitment_point. It removes an outdated warning that the method was non-asynchronous and that returning an error could cause a crash, and replaces it with …
Documentation-only changeRemoves outdated panic warningAdds retry/unblock guidance for signer errors
This commit changes the project's internal code-review workflow. It stops automatically assigning a human reviewer when a pull request is opened; instead, contributors must manually click a button to request a reviewer after first addressi…
This commit is purely a code-formatting cleanup. It removes `#[rustfmt::skip]` annotations and lets rustfmt reformat several functions in the routing/scoring module. No logic, behavior, or security properties of the code are changed.
This commit fixes a bug in LDK's Lightning channel reconnection logic after a splice (a way to resize a channel's on-chain funds). If one peer had already received the splice signatures but the other had not, and then they disconnected and…
Protocol-state inconsistency on reconnection after splice signature exchangePotential channel stall/force-close due to quiescence not being exited before commitment updateFuzzer-discovered edge case in Lightning splicing retransmission
This commit adds a new option for Lightning invoice creators to explicitly tell payers not to use multi-path payments (MPP) when paying an invoice. It does not change any enforcement rules; it only changes what feature bits are advertised …
New API surface for feature advertisement controlExplicit documentation that the method does not enforce single-HTLC receipt, shifting enforcement responsibility to callersNo removal or weakening of existing validation logic
This commit swaps the ID number used by an automated workflow that randomly assigns code reviewers. The old number pointed to a real person's account, so the workflow's assignments appeared to come from that person. The new number points t…
This commit removes a separate CI build step that tested the project with a special 'taproot' compiler flag. It is a workflow cleanup change, not a code change. There is no indication of a security vulnerability.
This commit adjusts the project's continuous integration (CI) test script to pin an older version of a build-time helper crate called `jobserver` when using older Rust compilers. It is a build compatibility fix, not a security patch, and d…
This commit updates a dependency used to talk to Esplora blockchain servers from version 0.12 to 0.13, switching the underlying HTTP library from reqwest to bitreq. It also removes two CI workarounds that pinned older versions of idna_adap…
Dependency version bump (esplora-client 0.12 -> 0.13)HTTP backend switch (reqwest -> bitreq) in a transitive dependencyRemoval of MSRV pins for idna_adapter and hyper-rustls
This commit only adds new test code. It exercises how a newer version of LDK exchanges saved channel data with the older LDK 0.2 release when a channel has a pending splice. There is no change to production logic, no bug fix, and no securi…
This change only affects an internal fuzz-testing harness, not production code. It makes the test harness crash with a clear error message if it encounters a ChannelMonitor event it doesn't know how to handle, instead of silently ignoring …
Test harness hardening onlyNo production code path modifiedNo cryptographic, network, or state-machine logic changed
This commit removes the 'Option' wrapper from several HTLC amount fields, making them required instead of optional. It is a cleanup/refactoring change that simplifies the code by assuming the amount is always known. The commit message fram…
Removal of Option wrapper for financial amount fieldsSerialization format change from optional to required TLV fieldsLoss of backward compatibility with older serialized monitor/channel state
Allow cancellation of pending splice funding negotiations
A user may wish to cancel an in-flight funding negotiation for whatever reason (e.g., mempool feerates have gone down, inability to sign, etc.), so we should make it possible for them to do so. Note that this can only be done for splice funding negotiations for which the user has made a contribution to.
73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Lower-priorityProduce FundingInfo::Contribution variants in ChannelMonitorby Wilmer Paulino · 7e806f97 · May 7, 2026 · 5 filesMessage 73 · AdequateTriage 0Details
Commit message · Wilmer Paulino
Produce FundingInfo::Contribution variants in ChannelMonitor
Similar to the `ChannelManager`, we expose the contributed inputs and outputs of a splice via `FundingInfo::Contribution` at the `ChannelMonitor` level such that we don't lose the context when the channel closes while a splice is still pending. This relies on tracking the `FundingContribution` that was provided to the `ChannelManager` prior to negotiating the new funding transaction. If no `FundingContribution` exists, then we continue to emit the `FundingInfo::OutPoint` variant.
73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Change FundingInfo::Contribution to expose contributed output scripts
Exposing the amounts for each output isn't very helpful because it's possible that they vary across over multiple splice candidates due to RBF. This commit changes `FundingInfo::Contribution` and several of the helpers used to derive it to be based on output scripts instead.
85/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode
Security candidateStrip Unicode `Cf` characters in `PrintableString`by Elias Rohrer · 1a01b5ae · May 7, 2026 · 1 fileMessage 86 · StrongHigh 72Details
Commit message · Elias Rohrer
Strip Unicode `Cf` characters in `PrintableString`
`PrintableString` is the sanitiser LDK uses to render untrusted strings (node aliases, BOLT-12 invoice / offer text, `UntrustedString`, LSPS messages, `lightning-invoice` descriptions) to logs and UI. It only replaced `char::is_control` matches (Unicode general category `Cc`) with U+FFFD, leaving the entire `Cf` (Format) category untouched.
That is the exact category covering the bidirectional override / isolate codepoints (U+202A..U+202E, U+2066..U+2069) and zero-width characters (U+200B..U+200D, U+FEFF) behind the "Trojan Source" attack family (CVE-2021-42574): a peer can set its alias / invoice description / offer fields to e.g. `safe\u{202E}cipsxe.exe`, which previously passed through verbatim while a human reader sees `safeexe.cips` — defeating the threat model `PrintableString` exists to defend against.
Replace `Cf` codepoints alongside `Cc` ones. The `Cf` ranges are inlined as a `matches!` table sourced from Unicode 16.0 to keep the change `no_std`-friendly with no new dependencies.
Co-Authored-By: HAL 9000 Signed-off-by: Elias Rohrer <dev@tnull.de>
86/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Links an issue, advisory, or supporting reference✓ Names security-relevant behavior explicitly
Why it was queued
explicit security language
AI analysis · High 72/100
This commit fixes a security gap in LDK's string sanitizer, PrintableString, which is used to display untrusted text like node names and invoice descriptions in logs and user interfaces. Previously it only stripped traditional control characters (like newlines and tabs) but left behind Unicode 'format' characters, including invisible bidirectional override characters and zero-width spaces. These can trick a human reader into seeing a different string than what the software processes—an attack family known as 'Trojan Source.' The patch now replaces those format characters with the standard replacement symbol (), so spoofed strings render safely.
Lower-priorityExpose probe status in recent paymentsby Elias Rohrer · 419908da · May 7, 2026 · 2 filesMessage 76 · AdequateTriage 0Details
Commit message · Elias Rohrer
Expose probe status in recent payments
Previously, `ChannelManager::list_recent_payments` didn't give us the means to discern 'real' payments from inflight probes. In https://github.com/lightningdevkit/ldk-node/pull/815 we found that we need a way to re-derive which probes are still pending so our accounting of inflight probing amounts is still correct after restart.
To this end, we here let callers distinguish liquidity probes while they are pending or abandoned.
Co-Authored-By: HAL 9000
Co-Authored-By: HAL 9000 Signed-off-by: Elias Rohrer <dev@tnull.de>
76/100 · AdequateMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Links an issue, advisory, or supporting reference
Lower-priorityDerive DiscardFunding inputs and outputs from contributions on promotionby Jeffrey Czyz · 51e60798 · May 7, 2026 · 2 filesMessage 73 · AdequateTriage 0Details
Commit message · Jeffrey Czyz
Derive DiscardFunding inputs and outputs from contributions on promotion
When a splice funding is promoted, produce FundingInfo::Contribution instead of FundingInfo::Tx for the discarded funding events. Each contribution is filtered against the promoted funding transaction's inputs and outputs, so only inputs and outputs unique to the discarded round are reported.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Lower-priorityCheck can_initiate_rbf in stfu handler before sending tx_init_rbfby Jeffrey Czyz · ffbb8fe6 · May 7, 2026 · 4 filesMessage 85 · StrongTriage 0Details
Commit message · Jeffrey Czyz
Check can_initiate_rbf in stfu handler before sending tx_init_rbf
If splice_locked is sent between our outgoing STFU and the counterparty's STFU response, the stfu() handler would proceed to send tx_init_rbf for an already-confirmed splice. Guard against this by re-checking can_initiate_rbf when entering quiescence. Disconnect because there is no way to cancel quiescence after both sides have exchanged STFU.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
85/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode
Remove unused NegotiationError and contributed_inputs_and_outputs methods
Now that splice_funding_failed_for! derives inputs and outputs from FundingContribution directly, remove the unused NegotiationError struct and into_negotiation_error methods from the interactive tx types, along with the into/to_contributed_inputs_and_outputs methods on ConstructedTransaction.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Lower-priorityDerive SpliceFundingFailed inputs from FundingContributionby Jeffrey Czyz · db45c833 · May 7, 2026 · 1 fileMessage 73 · AdequateTriage 0Details
Commit message · Jeffrey Czyz
Derive SpliceFundingFailed inputs from FundingContribution
Replace the maybe_create_splice_funding_failed! macro and splice_funding_failed_for method with a unified splice_funding_failed_for! macro that derives contributed inputs and outputs from the FundingContribution rather than extracting them from the negotiation state.
Callers pass ident parameters for which PendingSplice filtering methods to use: contributed_inputs/contributed_outputs when the current round's contribution has been popped or was never pushed, and prior_contributed_inputs/prior_contributed_outputs for the read-only persistence path where the contribution is cloned instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Lower-priorityFix output filtering in into_unique_contributionsby Jeffrey Czyz · 9c6cca6b · May 7, 2026 · 2 filesMessage 68 · AdequateTriage 0Details
Commit message · Jeffrey Czyz
Fix output filtering in into_unique_contributions
Filter outputs by script_pubkey rather than full TxOut equality. Outputs reusing the same address as a prior round are still considered committed even if the value differs (e.g., different change amounts across RBF rounds with different feerates).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
68/100 · AdequateMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Security candidateSimplify contribution pop in reset_pending_splice_stateby Jeffrey Czyz · 2eb939b1 · May 7, 2026 · 1 fileMessage 85 · StrongInformational 24Details
Commit message · Jeffrey Czyz
Simplify contribution pop in reset_pending_splice_state
The was_negotiated check is unnecessary because reset_pending_splice_state only runs when funding_negotiation is present, meaning on_tx_signatures_exchange hasn't been called yet. Since the feerate is only recorded in last_funding_feerate_sat_per_1000_weight during on_tx_signatures_exchange, the current round's feerate can never match it. So the contribution can always be unconditionally popped.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
85/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode
Why it was queued
signing boundary
AI analysis · Informational 24/100
This is a small code cleanup in the Lightning payment channel code that handles failed or aborted splice-in transactions. The change removes an unnecessary check when undoing a splice contribution, replacing it with an unconditional pop plus a debug-only sanity check. The commit message argues the old check could never trigger, so behavior should be unchanged. There is no direct evidence of a security bug, but any change to state-rollback logic in financial software warrants careful review because mistakes can leave funds in an inconsistent state.
AI review queuedRename SplicePending and SpliceFailed eventsby Jeffrey Czyz · cc7fb0f5 · May 7, 2026 · 10 filesMessage 68 · AdequateInformational 15Details
Commit message · Jeffrey Czyz
Rename SplicePending and SpliceFailed events
Rename Event::SplicePending to Event::SpliceNegotiated and Event::SpliceFailed to Event::SpliceNegotiationFailed. These names better reflect the per-round semantics: each negotiation attempt resolves to one of these two outcomes, independent of the overall splice lifecycle.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
68/100 · AdequateMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Why it was queued
signing or wallet pathsecond-pass: security-sensitive path
AI analysis · Informational 15/100
This commit is a simple rename of two public event types in the Lightning Dev Kit Rust library. `Event::SplicePending` is renamed to `Event::SpliceNegotiated`, and `Event::SpliceFailed` is renamed to `Event::SpliceNegotiationFailed`. The change is purely cosmetic and intended to make the event names better match their meaning (a single negotiation round outcome, not the overall splice lifecycle). No logic, serialization format, or security behavior is changed.
Lower-priorityEmit DiscardFunding before SpliceFailedby Jeffrey Czyz · 14c68199 · May 7, 2026 · 3 filesMessage 70 · AdequateTriage 0Details
Commit message · Jeffrey Czyz
Emit DiscardFunding before SpliceFailed
Reverse the event ordering at all emission sites so that Event::DiscardFunding is emitted before Event::SpliceFailed. If the user retries the splice when handling SpliceFailed, the contributed inputs would still be locked. A subsequent DiscardFunding would then incorrectly unlock inputs that are now committed to the new attempt. Emitting DiscardFunding first avoids this by ensuring inputs are unlocked before any retry occurs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Lower-priorityAdd FundingContribution to SpliceFailed eventby Jeffrey Czyz · 450eb645 · May 7, 2026 · 5 filesMessage 68 · AdequateTriage 0Details
Commit message · Jeffrey Czyz
Add FundingContribution to SpliceFailed event
Replace the abandoned_funding_txo and channel_type fields on Event::SpliceFailed with an Option<FundingContribution> from the failed round. Users can feed this back to funding_contributed to retry or use it to inform a fresh attempt via splice_channel.
Also makes FundingContribution::feerate() public so users can inspect the feerate when deciding whether to retry or bump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
68/100 · AdequateMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
AI review queuedAdd NegotiationFailureReason to SpliceFailed eventby Jeffrey Czyz · f0a8cebb · May 7, 2026 · 5 filesMessage 85 · StrongInformational 21Details
Commit message · Jeffrey Czyz
Add NegotiationFailureReason to SpliceFailed event
Each splice negotiation round can fail for different reasons, but Event::SpliceFailed previously gave no indication of what went wrong. Add a NegotiationFailureReason enum so users can distinguish failures and take appropriate action (e.g., retry with a higher feerate vs. wait for the channel to become usable).
The reason is determined at each channelmanager emission site based on context rather than threaded through channel.rs internals, since the channelmanager knows the triggering context (disconnect, tx_abort, shutdown, etc.) while channel.rs functions like abandon_quiescent_action handle both splice and non-splice quiescent actions.
The one exception is QuiescentError::FailSplice, which carries a reason alongside the SpliceFundingFailed. This is appropriate because FailSplice is already splice-specific, and the channel.rs code that constructs it (e.g., contribution validation, feerate checks) knows the specific failure cause. A with_negotiation_failure_reason method on QuiescentError allows callers to override the default when needed.
Older serializations that lack the reason field default to Unknown via default_value in deserialization. The persistence reload path uses PeerDisconnected since a reload implies the peer connection was lost.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
85/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode
Why it was queued
second-pass: broader security terminology
AI analysis · Informational 21/100
This commit is a user-facing diagnostic improvement, not a security fix. It adds a 'reason' field to the SpliceFailed event so Lightning node operators can tell why a splice negotiation failed (for example, peer disconnected, feerate too low, or counterparty aborted). It changes no cryptographic checks, access controls, or network behavior. The only code-level risk is a minor serialization compatibility change: old stored events without the new field default to 'Unknown', and the persistence reload path defaults to 'PeerDisconnected'.
Lower-priorityAttempt to unblock blocked monitor updates on startupby Matt Corallo · b0c312db · May 6, 2026 · 1 fileMessage 93 · StrongTriage 0Details
Commit message · Matt Corallo
Attempt to unblock blocked monitor updates on startup
When we make an MPP claim we push RAA blockers for each chanel to ensure we don't allow any single channel to make too much progress until all channels have the preimage durably on disk. We don't have to store those RAA blockers on disk in the ChannelManager as there's no point - if the ChannelManager gets to disk with the RAA blockers it also brought with it the pending ChannelMonitorUpdates that contain the preimages and will now be replayed, ensuring the preimage makes it to all ChannelMonitors.
However, just because those RAA blockers dissapear on reload doesn't mean the implications of them does too - if a later ChannelMonitorUpdate was blocked in the channel we don't have logic to unblock it on startup.
Here we add such logic, simply attempting to unblock all blocked `ChannelMonitorUpdate`s that existed on startup.
Code written by Claude.
Fixes #4518
93/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode✓ Links an issue, advisory, or supporting reference
Add public getters for `estimated_fee`, `inputs`, and `max_feerate`, and elevate `feerate` from `pub(super)` to `pub`. Together with the existing `value_added`, `outputs`, and `change_output`, this gives downstream consumers of `TransactionType::Splice` (notably LDK Node, which updates `PaymentDetails` from the broadcast callback) the data they need without reaching into the raw transaction.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AI review queuedExpose interactive funding candidates on broadcastby Jeffrey Czyz · 0d2ac33e · May 6, 2026 · 6 filesMessage 73 · AdequateInformational 18Details
Commit message · Jeffrey Czyz
Expose interactive funding candidates on broadcast
Replace TransactionType::Splice with TransactionType::InteractiveFunding so downstream consumers can update their own state tracking from the broadcast callback. The local contribution data isn't recoverable from the on-chain transaction, so the broadcast must surface it directly. Each candidate carries the participating channels and their local contributions; the broadcast lists every negotiated candidate — original first, then each RBF replacement — letting downstream reconcile any historical txid, not just the immediate predecessor.
The new variant is structured to be forward-compatible with batches and V2 (dual-funded) channel establishment, neither of which is implemented today. The new types are Writeable/Readable so downstream can persist them directly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Why it was queued
signing or wallet pathsecond-pass: security-sensitive path
AI analysis · Informational 18/100
This commit is a routine API improvement for the Lightning Dev Kit. It changes the information reported when a splice (or future dual-funded) transaction is broadcast so that downstream wallet software can see all negotiated versions of the transaction and each party's contribution. There is no indication of a security bug being fixed; it is a feature/refactoring change to expose richer data to consumers of the library.
Lower-priorityRoll back composite sub-handlers when one rejects `peer_connected`by Elias Rohrer · 5455058e · May 6, 2026 · 1 fileMessage 73 · AdequateTriage 0Details
Commit message · Elias Rohrer
Roll back composite sub-handlers when one rejects `peer_connected`
`composite_custom_message_handler!` expanded `peer_connected` to call every sub-handler and remember the last error, but never undo the already-succeeded ones. The `CustomMessageHandler::peer_connected` contract is that `PeerManager` will *not* invoke `peer_disconnected` when `peer_connected` returns `Err` — so any per-peer state allocated by an earlier sub-handler that returned `Ok` was leaked permanently once a later sub-handler returned `Err`.
A peer who can elicit `Err` from any sub-handler in the composite (feature-bit gate, banlist, etc.) could repeatedly reconnect to grow that leaked state without bound (slow resource DoS), and "currently connected" predicates in the leaking sub-handler would lie about peers that were actually rejected.
Mirror the rollback pattern `PeerManager` already uses for the four built-in handlers (`peer_handler.rs:2149-2188`): record each sub-handler's `peer_connected` result, and if any returned `Err`, call `peer_disconnected` on the ones that succeeded before propagating the failure.
Co-Authored-By: HAL 9000 Signed-off-by: Elias Rohrer <dev@tnull.de>
73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Security candidateDrop local chacha20poly1305 implementationby Abeeujah · 964a84fc · May 5, 2026 · 4 filesMessage 50 · ThinInformational 12Details
Commit message · Abeeujah
Drop local chacha20poly1305 implementation
Complete the migration process from the local chacha20poly1305 to the rust-bitcoin chacha20-poly1305 crate.
50/100 · ThinMessage clarity
✓ Descriptive subject✓ Provides an explanatory body
Why it was queued
cryptography-sensitive path
AI analysis · Informational 12/100
This commit removes the project's own implementations of the ChaCha20 stream cipher, Poly1305 message-authentication code, and the ChaCha20-Poly1305 combined encryption mode. It is described as the final step of migrating to the external 'rust-bitcoin chacha20-poly1305' crate. The change itself is a pure deletion of local code and module declarations; it does not add the replacement crate or change any call sites in this diff. There is no direct evidence in the commit that this fixes a security vulnerability.
Security candidateReplace local ChaCha20-Poly1305 with external crateby Abeeujah · a2cc67e7 · May 5, 2026 · 13 filesMessage 83 · StrongLow 36Details
Commit message · Abeeujah
Replace local ChaCha20-Poly1305 with external crate
Migrates ChaCha20-Poly1305 encryption from the local crypto module to rust-bitcoin's `chacha20-poly1305` crate.
Integrated the crate across all modules (Router, PeerStorage, Onion Utils, etc.).
Add the chacha20_poly1305_fuzz flag to fuzz config to after implementing the fuzz logic upstream.
83/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Mentions testing or verification
Why it was queued
fuzzing or regression evidencecryptography-sensitive pathsigning or wallet path
AI analysis · Low 36/100
This commit swaps out a home-grown ChaCha20-Poly1305 implementation for a widely reviewed external crate from the rust-bitcoin project. It is a routine refactoring/cryptographic-hardening change, not an obvious security fix. The diff shows careful translation of the old code to the new API, including fuzzing support and nonce handling. There is no direct evidence of a vulnerability being patched, but any crypto migration carries risk of subtle behavioral differences.
Lower-priorityRelease `OutputSweeper::pending_sweep` flag on future dropby Elias Rohrer · 6394d18b · May 5, 2026 · 1 fileMessage 85 · StrongTriage 0Details
Commit message · Elias Rohrer
Release `OutputSweeper::pending_sweep` flag on future drop
`regenerate_and_broadcast_spend_if_necessary` used `pending_sweep: AtomicBool` as a single-runner gate but only cleared the flag with an unconditional `store(false)` *after* the inner future resolved. If the caller's future was dropped while the inner await was `Pending` — which `tokio::time::timeout`, `futures::select!`, manual `JoinHandle::abort`, etc. all do — the reset never ran, leaving the flag stuck `true` and every subsequent call to the function short-circuiting with `Ok(())`.
Because `OutputSweeper` is what claims `SpendableOutputDescriptor`s back to the user's wallet after channel closure (including HTLC outputs with time-bounded recovery deadlines), a stuck flag turns into fund-loss exposure: time-sensitive HTLC sweeps simply stop happening, while every other code path keeps queueing new outputs to sweep, until the process is restarted.
Replace the trailing `store(false)` with an RAII `PendingSweepGuard` whose `Drop` impl always releases the flag — covering normal return, error, and cancellation alike.
Co-Authored-By: HAL 9000
85/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode
Security candidateValidate Esplora merkle proof against the block header's merkle rootby Elias Rohrer · b64efcda · May 5, 2026 · 1 fileMessage 78 · AdequateCritical 88Details
Commit message · Elias Rohrer
Validate Esplora merkle proof against the block header's merkle root
`EsploraSyncClient::get_confirmed_tx` parsed the SPV proof returned by the Esplora server but threw away the security check: the merkle root computed by `PartialMerkleTree::extract_matches` was discarded (`let _ = …`), and only the leaf-equality check (`matches[0] == txid`) remained. Anyone can construct a single-leaf partial tree advertising an arbitrary txid via `PartialMerkleTree::from_txids(&[txid], &[true])`, so this gate was vacuous.
A malicious or compromised Esplora server could therefore convince `EsploraSyncClient` that any transaction was confirmed in any block by returning `MerkleBlock { header: real_header, txn: forged_partial_tree }`, causing LDK to feed a synthesized `ConfirmedTx` into `Confirm` implementations such as `ChannelManager` / `ChainMonitor`. From there, the channel-funding / closing / HTLC flows would treat the transaction as confirmed at an attacker-chosen height, with consequences ranging from premature state transitions to force-close races.
Capture the merkle root returned by `extract_matches` and require it to equal `block_header.merkle_root`, matching the validation the Electrum sibling already performs via `validate_merkle_proof`.
Co-Authored-By: HAL 9000
78/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Names security-relevant behavior explicitly
Why it was queued
explicit security languagedefensive validationsigning or wallet path
AI analysis · Critical 88/100
This commit fixes a security bug in LDK's Esplora client. The client was supposed to verify that a transaction was really included in a Bitcoin block by checking a cryptographic proof (a merkle proof) from the Esplora server. But it only checked that the proof contained the right transaction ID, not that the proof actually connected to the real block header. Because a single-leaf proof can be forged for any transaction ID, a malicious or compromised Esplora server could trick LDK into believing any transaction was confirmed in any block. That could trigger wrong channel state changes, premature force-closes, or other fund-risking behavior. The fix makes the client compare the computed merkle root from the proof against the block header's merkle root, which is the same check the Electrum client already did.
Lower-priorityFix `StaticInvoice::is_offer_expired` to check the offer's expiryby Elias Rohrer · c005b11d · May 5, 2026 · 1 fileMessage 73 · AdequateTriage 0Details
Commit message · Elias Rohrer
Fix `StaticInvoice::is_offer_expired` to check the offer's expiry
The std-only `StaticInvoice::is_offer_expired` accessor delegated to `InvoiceContents::is_expired`, which compares `created_at + relative_expiry` against the current time — that is the *invoice*'s expiry, not the offer's. The `_no_std` sibling and `flow.rs:: enqueue_static_invoice` already treat the two as distinct checks.
A payer or forwarder using the std API to decide whether to honor a static invoice would therefore get the wrong answer in either direction: forwarding offers the issuer has already retired (when the invoice is still fresh), or refusing offers that are still valid (when the invoice has aged past its `relative_expiry` but the offer itself has no `absolute_expiry`).
Route the std accessor through `InvoiceContents::is_offer_expired` so both the std and no-std paths consult the offer's expiry.
Co-Authored-By: HAL 9000
73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context