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 updates the PostgreSQL database driver used by Eclair from version 42.7.11 to 42.7.12. It is a routine dependency bump by an automated tool. The commit itself does not say what bugs the new driver fixes, but small point-release…
Dependency version bump of a database driverPoint-release upgrade may include upstream security fixes, but none are named in the commitNo application code changes or direct vulnerability evidence in the diff
This commit updates Eclair's Bitcoin library dependency from version 0.48 to 0.49, which internally uses newer versions of bitcoin-kmp and secp256k1-kmp. The code changes only replace old property accesses (like `.txid`) with new method ca…
Dependency version bump for Bitcoin and secp256k1 cryptographic librariesSource changes are API adaptations (.txid -> .getTxid), not logic changesSecurity-critical validation code is touched (PSBT/transaction integrity checks against malicious Bitcoin Core)
This commit is a routine build-system update. It upgrades several Maven plugin versions, removes the git commit ID from one jar manifest field to avoid a build-time circular dependency, and adds an optional build profile for a fuzz-testing…
This commit closes a cross-site request forgery (CSRF) hole in Eclair's admin API. Before the change, a malicious web page visited by a node operator could silently submit authenticated API requests (for example, to send funds or close Lig…
New origin-check directive rejecting all requests with an Origin headerRemoval of CORS response headers from API responsesCSRF protection described in commit message and release notes
This commit is a routine post-release housekeeping change. It bumps the project version from 0.14.3 to 0.15.0-SNAPSHOT across several build files, re-enables a Maven trusted-checksum feature used for build verification, adds a placeholder …
No security-relevant code changesNo vulnerability indicatorsNo bug fixes or patches
This commit adjusts build packaging settings to make compiled releases more reproducible across different computers. It sets consistent file permissions and line endings for packaged documentation and runtime files. There is no indication …
This is a large security patch for the Eclair Lightning node that fixes multiple ways an attacker could steal funds, burn money to miners, or lock funds forever. The fixes include: preventing force-closes with un-publishable splice transac…
Force-close uses latest publishable commitment to avoid unconfirmable splice commit txsClosing fee bounded by maxClosingFeerate when local node pays feesNew max-funding-feerate configuration caps funding/splice miner fees
This change expands when Eclair will allow password-based authentication to a Tor control port. Previously, only loopback addresses (the same machine) were considered safe enough for password auth. Now, private/site-local and link-local ne…
Relaxation of authentication-method restriction for Tor control portPassword authentication now permitted on site-local and link-local addressesOriginal code explicitly rejected password auth for non-loopback addresses
This commit is a routine post-release housekeeping change. It bumps the project version from 0.14.2 to 0.15.0-SNAPSHOT, re-enables a Maven trusted-checksum feature used for build verification, adds a placeholder release-notes file, and del…
No security-relevant code changes indicating a vulnerabilityBoot.scala startup guard prevents accidental deployment of an unsafe development snapshotMaven trusted checksum verification is re-enabled, improving supply-chain/build integrity
This commit hardens Eclair's handling of the Lightning 'splicing' feature when a peer misbehaves. Splicing lets two nodes resize an open payment channel without closing it on-chain. The patch adds extra checks so that if a peer sends unexp…
Adds commitment-index consistency checks before completing splice/RBF funding attemptsRejects forbidden update messages while remote peer is quiescingRejects commit_sig during quiescence to prevent commitment-index desync
This commit adds a safety net to the Eclair Lightning node to limit how many incoming peer connections can sit unfinished before completing the cryptographic handshake. Previously, an attacker could open many TCP connections and leave them…
Resource-exhaustion mitigation: bounds unauthenticated incoming connections to prevent memory/file-descriptor/CPU exhaustionNew kill reason TooManyPendingConnections added to PeerConnection.KillReasonNew metrics incomingconnections.pending/evicted/rejected for monitoring abuse
This commit fixes three security issues in how Eclair connects to the Tor network and stores sensitive files. First, it changes the default Tor authentication from password to safecookie, and blocks password mode when the Tor control port …
Default authentication changed from password to safecookiePassword authentication rejected for remote Tor control portsTor cookie length validated to be exactly 32 bytes
This commit fixes a bug in the Eclair Lightning node where a peer could send a message containing both a correct standard signature and an incorrect partial signature. The old code would verify the correct signature but then store the inva…
Type-confusion between IndividualSignature and PartialSignatureWithNonce in channel messagesInvalid partial signature could be stored after valid individual signature was verifiedNew signatureFor helper enforces commitment-format-aware signature selection
This change makes the Eclair Lightning node force-close a payment channel if a peer tries to add a payment whose timeout value (cltv_expiry) is 500,000,000 or higher. Such large values are invalid according to the Lightning BOLT 2 specific…
BOLT 2 compliance check added for HTLC cltv_expiry >= 500,000,000Invalid cltv_expiry now triggers local error and channel force-closeOff-by-one fix in locktime threshold interpretation (<= changed to <)
This commit adds a new optional encrypted payload to Lightning payment fulfillment messages. It is a feature implementation, not a fix for an active vulnerability. The code does introduce a safety check: if a peer sends an oversized fulfil…
New cryptographic payload handling added to payment fulfillment pathSize limits and silent truncation applied to failure packets, fulfillment payloads, and attribution dataChannel force-close triggered on oversized peer fulfillment payload
This commit fixes five low-severity security or robustness issues in the Eclair Lightning node. It removes a risky type cast that could crash the node on corrupted channel data, forces encrypted cluster communication to prevent private dat…
Unsafe type cast removed from channel codecCluster mode now requires tls-tcp transportAPI error responses no longer include exception messages
This commit fixes a bug in the Eclair Lightning node where, after a restart, the node could be tricked into keeping the wrong incoming payments alive. An attacker could reuse the same payment identifier (payment_hash) from a legitimate in-…
Fixes a logic bug that could lead to forced channel closuresAttack vector: payment_hash reuse to pin unrelated HTLCsChanges identifier from payment_hash to unique (channel_id, htlc_id)
This commit only updates user documentation. It adds warnings that the Bitcoin node (bitcoind) should run on the same machine as Eclair, and if it runs remotely, operators must use a secure encrypted tunnel. No code was changed, so this pa…
Documentation-only changeNo code, configuration, or cryptographic modificationsDescribes pre-existing deployment risk rather than a new vulnerability
This commit fixes several bugs in Eclair's 'on-the-fly funding' feature, which lets a node open a Lightning channel and pay for it using future payment fees. The bugs could allow a malicious peer to make the node pay twice, lose money on f…
Double-payment vulnerability fixed: paymentAlreadyRelayed now checks commitment transactions in addition to pending local changes, preventing relay of already-cross-signed HTLCs after restart.Loss-of-funds vulnerability fixed: funded channels with unpaid future-HTLC fees are force-closed before upstream HTLCs are failed, avoiding a race where the peer fulfills a cross-signed downstream HTLC after we failed upstream.Upstream settlement gap fixed: preimages received after HTLC expiry are now relayed upstream, preventing the node from paying downstream without being paid upstream.
This commit tightens file and folder permissions for Eclair's sensitive data. It ensures that seed files (which protect the node's identity and Lightning channel funds) and the data directory are readable only by the owner on Linux/macOS s…
Hardening of seed file permissions to owner-only read/writeHardening of datadir and chaindir permissions to owner-onlyMigration path also re-permissions copied seed files
Expand any commit for its author, full message, clarity score, changed files, triage signals, analysis, and source link.
AI review queuedFix a batch of low-severity issues (#3355)by Bastien Teinturier · 06e0ff71 · Aug 19, 2026 · 9 filesMessage 88 · StrongModerate 52Details
Commit message · Bastien Teinturier
Fix a batch of low-severity issues (#3355)
* Remove explicit cast in channel codec
We used an explicit cast in our channel codec: this is safe for data that we created ourselves, but would throw an exception if our data is corrupted. It's trivial to be safe by removing the cast.
* Require `tls-tcp` when using cluster mode
We require that encryption is used between the front and backend nodes in cluster mode, otherwise private data would be exposed. This protects node from messing up their deployment configuration without realizing it.
* Remove exception details from failed RPCs
We don't return the exception message anymore for failed RPC calls, to avoid potentially leaking private information. This guarantees that only the node operator, with access to the logs, can see why RPC calls fail.
* Don't decode unknown onion message TLVs
We don't support any TLV for onion messages yet. Since onion messages can be spammy, we don't need to waste any ressources trying to decode unknown TLVs that we'll throw away anyway.
* Limit the number of onion messages self-hops
We only include ourselves multiple times in an onion message path when using dummy hops. If we're included too many times in a path, that's most likely a remote node messing with us: we just drop the message.
88/100 · StrongMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode✓ Links an issue, advisory, or supporting reference
Why it was queued
parser or protocol pathsecond-pass: broader security terminologysecond-pass: security-sensitive path
AI analysis · Moderate 52/100
This commit fixes five low-severity security or robustness issues in the Eclair Lightning node. It removes a risky type cast that could crash the node on corrupted channel data, forces encrypted cluster communication to prevent private data exposure, stops API error messages from leaking internal details, and makes onion message handling more resistant to spam by ignoring unknown data fields and limiting how many times a node can be inserted into a message path.
Security candidateExplicitly match on-the-fly HTLCs after a restart (#3357)by Bastien Teinturier · aa321d69 · Aug 19, 2026 · 3 filesMessage 93 · StrongHigh 72Details
Commit message · Bastien Teinturier
Explicitly match on-the-fly HTLCs after a restart (#3357)
When we restart our node, we look at HTLCs that have been received but not relayed yet: they must be failed back, otherwise we would let them in the incoming channel until their timeout is reached, which would force our peer to force-close.
There is an exception for HTLCs that are paying for an on-the-fly funded channel: we will explicitly retry relaying those HTLCs, even after a restart, because that's how we get paid for the funding fees. We were only matching them by `payment_hash`, which wasn't precise enough: an attacker could initiate an on-the-fly channel and then send unrelated HTLCs that use the same `payment_hash`, just to mess up with us and get some of our channels force-closed.
We already have the detailed information about on-the-fly HTLCs in our DB, so we now use that to match HTLCs on the corresponding `channel_id` and `htlc_id`, which guarantees uniqueness.
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
Why it was queued
explicit security language
AI analysis · High 72/100
This commit fixes a bug in the Eclair Lightning node where, after a restart, the node could be tricked into keeping the wrong incoming payments alive. An attacker could reuse the same payment identifier (payment_hash) from a legitimate in-flight channel funding request on unrelated payments. Because the old code matched only by payment_hash, those unrelated payments would be treated as part of the funding flow and not failed back. If left unresolved until their deadline, this could force the node to force-close its channels, costing money and disrupting service. The fix matches by the exact channel and HTLC identifier instead, which is unique.
Better documentation for remote `bitcoind` (#3359)
Our documentation didn't make it clear enough that `bitcoind` should ideally run on the same machine as `eclair`. If that's not possible, since `bitcoind` doesn't provide support for TLS for its RPC and ZMQ endpoints, the node operator MUST setup a secure tunnel (providing encryption and authentication) between `eclair` and `bitcoind`. If that isn't provided, a network attacker may drop or alter messages between `eclair` and `bitcoind`, which can lead to a loss of funds.
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
This commit only updates user documentation. It adds warnings that the Bitcoin node (bitcoind) should run on the same machine as Eclair, and if it runs remotely, operators must use a secure encrypted tunnel. No code was changed, so this patch does not by itself fix or introduce a security flaw.
Lower-priorityAdd more checks around funding amount and channel reserve (#3352)by Bastien Teinturier · 32b93b14 · Aug 13, 2026 · 6 filesMessage 81 · StrongTriage 0Details
Commit message · Bastien Teinturier
Add more checks around funding amount and channel reserve (#3352)
* Add configurable `max_funding_satoshis`
We add a configuration parameter to control the maximum allowed size of channels. This was previously limited by the wumbo feature bit, but when we activated wumbo on the network we removed any upper limit. It makes sense to still keep a reasonable bound on the channel size.
* Check channel reserve fundee requirements
We compare dust limits to channel reserves when we're fundee of a single-funded channel to match the BOLTs. Note that this is less clear for dual-funding, where the channel reserve is always set to 1% and those checks don't make as much sense and are replaced by a check on the dust limits bounds. When using 0-fee commitments, we'll want to allow high(ish) dust limits, which means that the reserve may not be met: this is fine, as it only slightly changes incentives but doesn't introduce a funds loss vector.
81/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Links an issue, advisory, or supporting reference
When restarting our node, we have a custom hook to avoid failing HTLCs downstream when they're used with on-the-fly funding, because we want to retry relaying those HTLCs. That doesn't apply to on-chain failures though, because at that point the downstream channel has been closed.
* Don't relay on-the-fly HTLCs twice after restart
Before relaying on-the-fly HTLCs, we verify that they aren't already being relayed. We only look at the pending changes, because once the HTLCs are relayed we change their in-memory state in the Peer actor.
But if we restart after cross-signing on-the-fly HTLCs, we previously would relay them again, thus paying the downstream user twice. We now also look at the commitment transactions to avoid that.
* Force-close unpaid on-the-fly channels
When we fund an on-the-fly channel for which fees must be paid in the follow-up HTLCs, our peer may act maliciously and ignore those HTLCs when we relay them after funding the channel. We've already funded the channel so it's too late to recover the on-chain fees we've paid, so we previously just failed back the corresponding upstream HTLCs and gave up on relaying them to the funded channel.
However, the HTLCs may already be cross-signed and pending on the funded channel, which means that our peer could fulfill it and get paid while we have failed the corresponding upstream HTLCs. In that case, we lose funds. We can only fail the upstream HTLCs if we're sure that we haven't relayed them yet,
Since obtaining this state is asynchronous and complex, we now opt-in to a safer approach: we force-close the channel, check its commitments, and only fail the upstream HTLCs that weren't relayed. If they have been relayed, they will automatically be failed back when our HTLC-timeout transaction confirms.
* Reject on-the-fly payment for batch of `payment_hashes`
While the protocol supports batching `payment_hashes`, we currently only use it for one `payment_hash` at a time. It's thus safer to restrict it to this to prevent potential abuse. We also explicitly reject the case where an attacker tries to insert the same `payment_hash` twice to mess up our state.
* Correctly relay preimages upstream after timeout
If we receive the preimage for an on-the-fly payment *after* the HTLC has timed out, we still need to relay that preimage upstream, otherwise we've paid downstream without being paid upstream.
98/100 · StrongMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode✓ Mentions testing or verification✓ Links an issue, advisory, or supporting reference
Why it was queued
explicit security languagesigning boundarysigning or wallet path
AI analysis · High 78/100
This commit fixes several bugs in Eclair's 'on-the-fly funding' feature, which lets a node open a Lightning channel and pay for it using future payment fees. The bugs could allow a malicious peer to make the node pay twice, lose money on force-closed channels, or fail to collect incoming payments after timeouts. The patch adds checks to prevent double-relaying payments, force-closes channels when fees are unpaid, and ensures preimages are still forwarded upstream even after an HTLC timeout.
Lower-priorityUse `min_final_expiry_delta` in trampoline test handler (#3353)by Bastien Teinturier · 8436c50e · Aug 13, 2026 · 1 fileMessage 91 · StrongTriage 0Details
Commit message · Bastien Teinturier
Use `min_final_expiry_delta` in trampoline test handler (#3353)
We use the invoice's `min_final_expiry_delta` in the test trampoline payment FSM (which isn't used for any real payment, it is only there to allow cross-compat tests with other implementations).
When not using Bolt11, we increase the fallback value to 42, which is what LDK uses by default.
We also add 1 block in case we're late in our view of the blockchain.
91/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Mentions testing or verification✓ Links an issue, advisory, or supporting reference
Security candidateHarden permissions of seeds and datadir (#3340)by rorp · 17edd765 · Aug 13, 2026 · 4 filesMessage 53 · ThinModerate 62Details
Commit message · rorp
Harden permissions of seeds and datadir (#3340)
53/100 · ThinMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Links an issue, advisory, or supporting reference! No meaningful explanatory body
Why it was queued
defensive validationcredential or privilege statecryptography-sensitive path
AI analysis · Moderate 62/100
This commit tightens file and folder permissions for Eclair's sensitive data. It ensures that seed files (which protect the node's identity and Lightning channel funds) and the data directory are readable only by the owner on Linux/macOS systems. Previously, these files could inherit looser default permissions, potentially allowing other local users on the same machine to read secrets and steal funds. Windows is unaffected because it uses a different permission model.
While `DEBUG` logs shouldn't be activated on mainnet, it is dangerous that they expose key material. We remove those logs.
* Remove onion shared secrets from unparsable failure logs
When receiving a failure that we couldn't parse, we added the shared secrets in the logs to help us troubleshoot (because we've seen that error frequently on our node). It didn't let us figure out the issue, which most likely comes from a buggy intermediate or final node. We now remove those secrets from the logs for safety.
* Make incoming connection tracker idempotent
If we receive multiple times a request to track a given node, we ignore the redundant ones.
* More robust network DB clean-up on restart
On restart, we remove `channel_update`s that we cannot decode from our network DB. The way the code was written could be an issue depending on the postgres driver, because it potentially interleaved SELECT and DELETE clauses. It apparently doesn't matter for our current version of the postgres driver, but it's more future-proof to explicitly split the SELECTs from the DELETEs.
* Check wake-up config before trying message wake-up
We didn't check the wake-up config parameter when relaying onion messages, which wasted resources by creating actors that would be useless.
* Include wallet node_id encoding when resolving blinded paths
When resolving the introduction point of a blinded path and checking whether one of the nodes is ourselves, we must check that with all potential encodings, including the wallet-reserved one.
* Don't include extraneous HTLCs in trampolinefee calculation
When relaying a trampoline payment, we must ensure that we don't include extraneous payments (that are rejected), otherwise we will use a very large route fee budget.
* Correctly clean up MPP payment-initiator state
When directly crafting MPP payments using the `sendtoroute` API, we use the child payment ID as tracking key in the `PaymentInitiator` internal state. If the payment fails, the `PaymentFailed` event will correctly use that ID, so the state will be cleaned up. But if the payment succeeds, the `PaymentSent` event uses the *parent* payment ID so the state wasn't correctly cleaned up. We now clean up the child state as well.
* Explicitly handle empty payment types
We've recently improved our liquidity ads codec, but we weren't properly handling the case where no payment types are provided (even though this will likely be rejected by remote nodes).
88/100 · StrongMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode✓ Links an issue, advisory, or supporting reference
Why it was queued
cryptography-sensitive pathparser or protocol path
AI analysis · Moderate 64/100
This commit is a bundled maintenance patch for the Eclair Lightning node. It removes sensitive cryptographic keys and shared secrets from debug/error logs, fixes a bug where rejected payments could still be counted when calculating trampoline routing fees, prevents state leaks in manually crafted multi-part payments, makes incoming-connection tracking idempotent, avoids unnecessary peer wake-up attempts, handles an edge case in liquidity-ads encoding, separates database SELECT and DELETE operations for safety, and correctly recognizes wallet-encoded node IDs when resolving blinded payment paths. Several of these changes have clear security relevance, particularly the logging cleanup and the trampoline-fee fix, but they are defensive hardening and bug fixes rather than a single critical vulnerability.
Improve defenses against malicious bitcoin RPC endpoint (#3343)
* Verify `txid` returned by Bitcoin Core
When using Bitcoin Core RPC, we now validate that the returned transaction matches the request. This is part of a defense-in-depth strategy in case our batching client messes up the order of RPC responses.
* Use keyed requests in bitcoin batch RPC client
We previously only relied on the order of requests to match responses that we receive from bitcoind, but there is no guarantee that the order will be preserved. In practice it seems to be the case, but we should be resilient if that changes.
We now use unique request IDs and match the corresponding response using this ID instead of relying on position only.
* Verify amount funded by Bitcoin Core wallet
We verify that the amount contributed by our Bitcoin Core wallet matches what we requested. A malicious Bitcoin Core may underfund or overfund, which in both cases is undesirable behavior.
91/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Mentions testing or verification✓ Links an issue, advisory, or supporting reference
A `query_channel_range` is a few dozen bytes to send, but answering one forces us to scan our whole routing table, compute a checksum for every channel_update we know and send back megabytes of data. We introduce rate-limits for gossip queries, ack them only when they've been processed, and make processing them more efficient:
- Add per-connection rate-limits for `query_channel_range` per connection. Queries that we drop are still acked, otherwise the transport would stop reading from the connection. The new`router.sync.max-queries-per-second` defaults to 10: peers only need to send a handful of those per connection, so this doesn't affect normal syncing.
- Only acks a query once we've sent our replies: acking first releases the transport-level back-pressure while we're still working, which lets queries pile up in the router's mailbox.
- Ignore gossip queries that are for another chain: we were answering them, which leaked our routing table to nodes that aren't even on our network. We already had that check for `gossip_timestamp_range`.
- cache the timestamps and checksums of our channel updates in `PublicChannel`, instead of re-serializing every update we know on every incoming query. The instance is replaced whenever an update changes, so the cache is transparently invalidated.
- remove the spent channels with `--` instead of rebuilding the whole channels map with `filterNot`.
- drop the `keep` filter in `handleQueryChannelRange`: it built a copy of our whole routing table, and `split` already restricts ids to the requested range as it iterates them in block height order.
* Bound the work a query_short_channel_ids can create
Ignore duplicate `short_channel_id`s: the spec doesn't forbid them, but a query is capped at 65kB while our reply isn't capped at all, so repeating the same scid was worth ~90x amplification to a peer. We already tracked the node announcements we had sent for that reason, we now track channel ids the same way.
Reject queries whose `encoded_query_flags` don't decode to exactly one flag per `short_channel_id`, and queries that arrive before we've sent the `reply_short_channel_ids_end` for the previous one. BOLT 7 explicitly allows sending a `warning` for both, and forbids senders from doing either.
The dead `numca`/`numcu` accumulators in `processChannelQuery` are removed: they were never incremented and the result was discarded. The counts that we log and report to Kamon come from the callbacks and are unchanged.
* Bound the sync state a peer can make us keep
Our peer decides when a routing table sync ends, so we can't let it dictate how much we buffer for it. Cap the number of `query_short_channel_ids` we queue for a given peer during a sync with `router.sync.max-queries-per-sync` (default 2000, i.e. 200 000 channels at the default chunk size, several times the size of the network). Past that we ignore the extra channel ids and keep draining the queries we already have: the sync is then incomplete for that peer, but gossip and our other sync peers make up for it.
Ignore `reply_short_channel_ids_end` messages that don't answer a query we have in flight. We were popping and sending the next query on any of them, so a peer could send one right after answering our `query_channel_range`, when we have nothing in flight: we would log "sync complete", drop our sync state, and ignore the rest of its replies as unsolicited.
Note that `reply_short_channel_ids_end` carries nothing that identifies the query it answers, so we can't do better than tracking whether we're waiting for one: a peer that answers our queries can still send extra end messages to drain our pending queries faster than we intended. That is now bounded by the cap above, and the queries only go back to that peer.
`Syncing.started` is replaced by the explicit `queryInFlight` flag it was being used as a proxy for.
* Don't drop queued queries when starting a sync
`addToSync` built a fresh `Syncing` in the branch that sends a query right away, which discarded `current.remainingQueries`. That branch used to be reached only when we had no state at all for that peer, but since #1587 we pre-create a `Syncing(Nil, 0)` entry when we send our `query_channel_range`, so it now overwrites real state instead of creating the first one.
This is not currently a bug as `remainingQueries` is always empty there today: it's an implicit invariant that nothing enforces. We pop from the queued list instead of overwriting it, so we can never silently drop queries.
Also narrow `Syncing.remainingQueries` to `List[QueryShortChannelIds]`: that's the only thing we ever put in it, and `addToSync` already returns that type.
* Rate-limit query_short_channel_ids
Same reasoning as for query_channel_range.
* Router: forget sync state for peers that are disconnected
88/100 · StrongMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode✓ Links an issue, advisory, or supporting reference
Why it was queued
defensive validation
Security candidateMultiple bug fixes found by AI scanning (#3346)by Bastien Teinturier · 0c4ddc4d · Aug 12, 2026 · 5 filesMessage 88 · StrongHigh 74Details
Commit message · Bastien Teinturier
Multiple bug fixes found by AI scanning (#3346)
* Fix 0-fee commitments fee bumping with remote-main
When using 0-fee commitments, if our peer publishes their commitment and our main output is large enough, we don't need to use a wallet input to pay RBF fees, we can directly do it using our main output.
However, we didn't take into account the whole package weight when doing so: this means that there was a balance range where we would not correctly bump the commit tx to the target feerate.
* Retry transaction publishing on unclassified failures
We classify bitcoind publish failures by substring-matching the RPC error message. Any rejection that doesn't match any of the RPC error messages that we know would previously not be retried.
This was dangerous, as it could cause us to abandon a time-sensitive transaction, which could cause loss of funds. We now eagerly retry when we cannot classify the RPC publish failure.
* Fix `channel_ready` using invalid musig2 nonce if RBF
We must use `commitments1` instead of `d.commitments` when creating our `channel_ready` message to ensure that we use the correct musig2 nonce for taproot channels. Otherwise, if we have multiple RBF attempts and the ony confirming is *not* the latest one, we will use the wrong nonce.
* Fix out-of-bound array access in payment FSM
Remote failures can be manipulated to trigger an out-of-bound array access which crashes the payment lifecycle actor.
88/100 · StrongMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode✓ Links an issue, advisory, or supporting reference
Why it was queued
nonce handling
AI analysis · High 74/100
This commit fixes four separate bugs in the Eclair Lightning node, all reported as found by AI scanning. Two of the bugs can cause loss of funds: one miscalculates transaction fees when bumping a channel close, and another could abandon time-sensitive transactions on unrecognized Bitcoin RPC errors. A third bug could use the wrong cryptographic nonce after a channel funding RBF, and a fourth could crash the payment actor via a maliciously crafted remote failure message. The commit is a straightforward set of fixes, but it is partial in the sense that it does not include broader hardening beyond the specific bugs identified.
We improve the performance of the liquidity ads codec by ignoring unknown payment types, and simply checking whether the payment types we support are activated or not.
* Reject node_announcement with invalid liquidity TLV
If the liquidity ads TLVs is present but with empty fields, we fail to correctly re-encode it. We must reject it immediately instead.
76/100 · AdequateMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Links an issue, advisory, or supporting reference
Why it was queued
parser or protocol pathsecond-pass: security-sensitive path
AI analysis · Moderate 50/100
This commit fixes a bug in how Eclair handles 'liquidity ads' data embedded in Lightning node announcements. Previously, if a peer broadcast a node_announcement containing a liquidity-ads field with empty funding rates or empty payment types, the node could not re-encode the message correctly, which could cause it to relay or store invalid gossip. The patch now rejects such malformed announcements immediately. It also improves codec performance by storing the raw payment-type bitfield instead of eagerly decoding unknown payment types.
Correctly handle unknown flags in `channel_update` (#3341)
We previously ignored unknown `channel_flags` and `message_flags` in the channel updates we received at decoding time, which means we would always replace them by `0` when re-encoding the channel update before forwarding it. If a flag that we don't understand was set to `1`, the signature becomes invalid.
In order to be future-proof, we must preserve the values of unknown flags during a codec round-trip: this way old eclair nodes will still correctly relay future channel updates that contain flags that haven't yet been specified.
98/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✓ Names security-relevant behavior explicitly
Why it was queued
signing boundaryparser or protocol path
AI analysis · Moderate 64/100
This commit fixes a bug in how Eclair handled unknown flag bits in Lightning 'channel_update' messages. Previously, the software silently cleared any flag bits it did not recognize when re-encoding a message before forwarding it. Because those flag bits are part of the signed data, clearing them made the digital signature invalid. The fix now preserves all unknown flag bits through a decode-encode round trip, so older Eclair nodes can still correctly relay future channel updates that use newly defined flags.
AI review queuedBack to dev (#3339)by Bastien Teinturier · ee7d9f6d · Jul 29, 2026 · 8 filesMessage 36 · OpaqueInformational 15Details
Commit message · Bastien Teinturier
Back to dev (#3339)
After the v0.14.1 release.
36/100 · OpaqueMessage clarity
✓ Subject identifies a change✓ Links an issue, advisory, or supporting reference! No meaningful explanatory body
Why it was queued
second-pass: opaque commit message
AI analysis · Informational 15/100
This commit is a routine post-release housekeeping change. It bumps the project version from 0.14.1 to 0.15.0-SNAPSHOT, re-enables a Maven trusted-checksum feature used for build verification, adds a placeholder release-notes file, and includes a safety guard that refuses to start the development snapshot unless a special override flag is set. There is no security vulnerability in the diff itself; the startup guard is an intentional protective measure, not an exploit.
✓ Descriptive subject✓ Names a concrete action or component✓ Links an issue, advisory, or supporting reference! No meaningful explanatory body
AI analysis · Low 45/100
This commit is the packaging of Eclair v0.14.1. It mostly changes version numbers and release notes, plus two operational tweaks: it turns off Maven's trusted-checksum post-processor and removes a startup guard that previously refused to run. The release notes describe the release as a routine patch with bug fixes and performance improvements, but also mention a Bolt12 fee-discount feature that was disabled because it could put nodes 'at risk' if used with custom plugins. No CVE or independent security report is referenced in the materials.
In https://github.com/ACINQ/eclair/pull/2993, we introduced a mechanism in the default Bolt12 offer handler to let the recipient pay the fees of the blinded paths they include in their Bolt12 invoices, instead of the payer having to pay fees for privacy chosen by the recipient (when the recipient decides to use a "real" blinded path with external nodes they don't control).
This wasn't correctly taking MPP into account: payers could split the payment in many tiny parts such that each part used the whole path fee discount. As a result, the payer would have still paid the whole amount but most of it would be collected by intermediate nodes inside the path instead of the recipient, which isn't the goal.
We're thus disabling this feature: we'll need a cleaner protocol to correctly account for MPP with base fees. Bolt12 isn't used yet by merchants so it's fine: we'll wait for recipients to adopt it before deciding how we introduce a blinded path fee discount feature (if this is something that users request). Note that we also recommend users to implement their own offer handler to customize their blinded paths, if they care about privacy, instead of using the default handler which is mostly there as a reference.
81/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Links an issue, advisory, or supporting reference
AI analysis · Moderate 60/100
This commit removes a fee-discount feature for a new kind of Lightning payment (Bolt12 offers). The old feature let the seller pay routing fees for the hidden 'blinded' path they chose for privacy. But when a payer split a payment into many tiny pieces, each piece could claim the full discount, so most of the money would go to routing fees instead of the seller. The patch disables the discount to stop that abuse. It is a defensive fix, not an active exploit being patched in deployed code, because Bolt12 merchant use is still rare.
If the first DB write of a channel fails, we want to abort the channel immediately, otherwise our state may be unusable. If for some reason we already have a channel (for example because of a partial restore from a DB backup), we want to avoid overwriting this state as well.
* Add global `channel_id`s collision resistance
We add a global, concurrent map that keeps track of every temporary and final `channel_id` being used. We always add to this map before creating channel actors or transitioning to a final `channel_id` (and thus before storing channel data in the DB).
We only remove from that map when a channel actor dies: no other channel can be associated with the corresponding temporary or final `channel_id` since the channel was created after registering the IDs.
78/100 · AdequateMessage clarity
✓ Descriptive subject✓ Provides detailed explanatory context✓ Explains rationale or failure mode✓ Links an issue, advisory, or supporting reference
Why it was queued
signing or wallet pathsecond-pass: security-sensitive path
AI analysis · Moderate 60/100
This commit hardens the Eclair Lightning node against two related problems when opening payment channels: it prevents the same channel ID from being reused by two different channels at the same time, and it aborts channel creation if the very first database write fails (for example because a channel with that ID already exists from a backup). Before this change, a colliding or partially-restored channel ID could cause one channel's state to overwrite another's, potentially leading to loss of funds or an inconsistent node state.
Apply RBF limits to remote closing transactions (#3331)
* Apply RBF limits to remote closing transactions
When using `option_simple_close`, we didn't apply explicit rate-limits to remote closing transactions, apart from the fact that the feerate must be higher for each attempt.
There is no good reason to make a large number of RBF attempts when closing a channel cooperatively, so we apply the same rate-limits we use for funding.
* Bound the number of local closing transactions
We apply the BOLTs recommendation for the maximum number of closing transactions we create when using the legacy closing protocol (not `option_simple_close`). We previously restricted remote closing transactions, but we now also apply it to our local transactions.
* Apply the maximum attempts limit to splice RBF
We previously only applied the rate-limit (X attempts every Y blocks) but we didn't apply the maximum attempts limit. The risk is that we may end up with a splice that is stuck unconfirmed, but will eventually confirm, unless the peer is malicious and the feerate was very badly estimated (in which case they would have found a way to prevent the splice from confirming anyway).
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
AI analysis · Moderate 52/100
This commit adds rate limits and maximum attempt caps for Replace-By-Fee (RBF) closing transactions in the Eclair Lightning node. Previously, a peer could repeatedly propose new closing transactions without strict limits, which could waste computing resources, storage, and network bandwidth. The change also applies the same limits to local and splice RBF attempts, aligning with Lightning protocol recommendations and reducing the risk of abuse or accidental resource exhaustion.
``` If batch_size is not strictly greater than 1: - MUST ignore the start_batch message. - SHOULD send a warning. ```
76/100 · AdequateMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Links an issue, advisory, or supporting reference
AI analysis · Low 25/100
This commit tightens validation of a Lightning network peer message called start_batch. Previously, the software only rejected batch sizes larger than 20. Now it also rejects batch sizes of 0 or 1, which the protocol specification says must be ignored with a warning. The change is a standards-compliance fix; it does not by itself look like a critical vulnerability, but it removes a case where a peer could request a meaningless batch and the node would accept it.
If our peer is buggy, or if we have a bug in our message queue, we may receive duplicate settlement messages for pending HTLCs. It is fine to handle them and relay the settlement downstream (instead of immediately force-closing), but we shouldn't store the duplicate settlement in the remote changes, otherwise it will trigger a force-close when exchanging `commit_sig`.
88/100 · StrongMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode✓ Links an issue, advisory, or supporting reference
AI analysis · Moderate 60/100
This patch fixes a bug in Eclair's Lightning payment channel code. If a buggy peer (or internal message queue bug) sent the same HTLC settlement message twice, Eclair would store the duplicate in its list of pending remote changes. Later, when signing the next commitment, that duplicate would be treated as a conflicting update and trigger an unnecessary force-close of the channel. The fix ignores duplicate settlement messages instead of storing them again, while still allowing the first one to be relayed downstream. It also still force-closes if a conflicting (different) settlement arrives for the same HTLC.
We previously rejected Bolt12 invoices when a reply path was provided in the onion message. This wasn't in the spec, and it could make sense to provide a specific reply path with an invoice in case the payer considers the invoice invalid and wants to send back an invoice_error to inform the recipient.
This created compatibility issues with LDK.
Fixes #3322
76/100 · AdequateMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Links an issue, advisory, or supporting reference
Why it was queued
parser or protocol pathsecond-pass: security-sensitive path
AI analysis · Low 30/100
This commit loosens Eclair's validation of BOLT12 invoice onion messages so that invoices may now include a reply path. Previously, Eclair rejected invoices that carried a reply path, which caused compatibility problems with LDK nodes. The change is framed as an interoperability fix, not a security fix, and it tightens some related validation rules at the same time.
When our peer sends us an invalid `tx_signatures`, we processed it and ignored the failure when we've already sent our own `tx_signatures`, because the transaction may be broadcast and may confirm anyway.
We now stop processing those invalid `tx_signatures` repeatedly: if our peer sends us more than 3 invalid `tx_signatures` for a given funding transaction, they're definitely buggy so we'll just wait for the transaction to confirm without trying to obtain the fully signed one locally.
We also now avoid unnecessary DB writes on `shutdown`. We don't need to write to the DB every time we receive `shutdown` from our peer, since the BOLTs require `shutdown` to be retransmitted on reconnection.
88/100 · StrongMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode✓ Links an issue, advisory, or supporting reference
Why it was queued
signing boundary
AI analysis · Low 47/100
This update changes how the Eclair Lightning node handles repeated bad 'tx_signatures' messages from a peer during dual-funded channel opens and splices. Previously, every bad signature was processed and logged, which could waste CPU and disk writes and might be abused to keep a node busy. Now, after three bad signatures for the same funding transaction, the node stops processing them and just waits for the on-chain confirmation. The patch also removes unnecessary database writes when receiving repeated 'shutdown' messages. The commit message frames this as a robustness improvement against buggy or malicious peers, not as a critical vulnerability fix.
This release contains a new index which we need for #3279.
68/100 · AdequateMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Provides an explanatory body✓ Links an issue, advisory, or supporting reference
AI analysis · Informational 15/100
This commit simply updates Eclair's required Bitcoin Core version from 30.x to 31.1. It changes download URLs, SHA-256 checksums, documentation, a runtime version check, and a test path. There is no security vulnerability in this change itself.
Reject `temporary_channel_id` duplicates early (#3324)
We previously rejected duplicate `temporary_channel_id` immediately, but we didn't immediately reject `temporary_channel_id`s that conflict with a *final* `channel_id` with the same peer: the rejection would happen later in the flow when transitioning from temporary to final IDs, which made debugging harder.
Since the channel interceptor step isn't atomic, we must check for duplicate channel IDs *after* rate-limiting, to ensure that we don't try inserting an entry in the channels map that is already there.
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
AI analysis · Low 37/100
This change tightens how Eclair handles incoming Lightning channel requests. It now rejects a new channel's temporary ID if it collides with an existing final channel ID for the same peer, and it re-checks for collisions after rate-limiting. Previously, some collisions were caught only later, which could make the node misbehave or make problems harder to diagnose. The patch is defensive hardening rather than a clear exploit fix.
Lower-priorityReject incoming HTLCs with a high `cltv_expiry` (#3323)by Bastien Teinturier · 7fb94601 · Jul 8, 2026 · 4 filesMessage 93 · StrongModerate 52Details
Commit message · Bastien Teinturier
Reject incoming HTLCs with a high `cltv_expiry` (#3323)
We currently reject HTLCs with a `cltv_expiry` higher than 2 weeks in the future when sending them (in the `sendAdd` method). That's because they would lock up our funds for a long period of time if our peer decided to force-close. Also, a large `cltv_expiry` makes slow jamming easier.
We now apply the same limits to incoming HTLCs for consistency (since they may differ by `cltv_expiry_delta`). Note that we don't do it in the `receiveAdd` function, which would trigger a force-close. We just accept those HTLCs and then fail them, since it is harmless to have them only temporarily in our commitment as long as we don't relay.
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
AI analysis · Moderate 52/100
This change tightens a safety limit on the Bitcoin Lightning Network node Eclair. Previously, Eclair already refused to send outgoing payments whose refund deadline (the 'cltv_expiry') was more than about two weeks in the future, because that would lock up funds for too long and make certain spam/jamming attacks easier. Now it also rejects incoming payments with similarly distant deadlines, but it does so gracefully by accepting the payment into the channel and then immediately failing it, rather than force-closing the channel. This is a defensive hardening patch, not a fix for an active exploit, and it reduces the risk of funds being locked up or the node being used for 'slow jamming' of the network.