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 adds validation checks for BOLT 12 invoices in the LND Lightning node software. It ensures invoices contain required fields (creation time, amount, payment hash, node ID, payment paths), match their originating invoice requests…
New validation gate added to Invoice.Encode() to reject malformed invoices before serializationReader rejects unknown even invoice TLV types and unknown even feature bitsReader enforces chain compatibility against activeChain
This commit is a hardening and cleanup of a GitHub Actions workflow that automatically labels pull requests by severity. It does not change any LND node code, wallet logic, or network protocol. Instead, it splits the workflow into two jobs…
Principle of least privilege: write token moved out of the model-bearing jobUntrusted input (model-generated comment) sanitized before privileged API useExternal action pinned to immutable commit SHA instead of mutable tag
This commit adds a new RPC called SubmitPackage to LND's WalletKit. It lets users submit a group of related Bitcoin transactions together so a zero-fee parent can be accepted because a later child transaction pays its fee. This is a featur…
New RPC endpoint gated by onchain:write macaroon permissionPackage size bounded to 25 transactions to limit deserialization workFee-rate ceiling passed through to backend; explicit 0 disables limit
This commit adds validation checks for BOLT 12 invoice requests in the LND Lightning node. It ensures that invoice requests follow protocol rules when being created (written) and received (read), rejecting malformed or non-compliant reques…
New input validation functions added for protocol messagesValidation now runs before encoding, preventing malformed outbound messagesOverflow guard added for amount*quantity calculation
This is a large dependency upgrade for the LND Lightning node software. It moves LND from older btcd Bitcoin library packages to new 'v2' packages and updates related wallet and network libraries. The commit is almost entirely mechanical i…
Large dependency upgrade touching core Bitcoin primitives (wire, txscript, chainhash, btcutil, psbt, address)Migration to new v2 module layout with API changes in address handlingPins new upstream releases (btcd 0.26.0, btcwallet 0.17.0, neutrino 0.18.0, lightning-onion 1.4.0) that may include undisclosed fixes
This commit fixes a bug in LND's DNS seed bootstrap code that could crash the node. The code assumed every record in a DNS response was an SRV record, so a non-SRV record (like a normal A or CNAME record) would cause a panic. The fix safel…
Unconditional type assertion panic in DNS fallback pathMissing bounds check on LookupHost result before array indexingMissing network deadline on manually dialed DNS TCP connection
This commit removes a temporary security workaround in a Go module file. The workaround forced the use of a newer, fixed version of a compression library (xz) to avoid a known historical vulnerability. The commit message says the library i…
Removal of a dependency-level vulnerability workaroundReference to historical advisory GHSA-25xm-hr59-7c27 in deleted commentNo code changes; only go.mod cleanup
This commit removes an old workaround in LND's dependency file (go.mod) that pinned a safe version of the 'xz' compression library. The workaround was originally added because another dependency once pulled in a vulnerable version of xz. T…
Removal of a dependency override that was a security mitigation for CVE-2021-29482Commit explicitly references the original GHSA advisory (GHSA-25xm-hr59-7c27)No actual downgrade or re-introduction of the vulnerable module is visible in the diff
This commit is a cleanup-only change that removes unnecessary loop-variable copies in Go test files. Since Go 1.22, loop variables are already scoped per-iteration, so the old `x := x` workarounds are redundant. The change affects only tes…
This commit updates a dependency version in LND's build files. It bumps the internal 'kvdb' submodule from version 1.5.0 to 1.5.1 so that downstream projects importing kvdb directly do not pull in an older, vulnerable telemetry library (Op…
Dependency bump explicitly motivated by a known vulnerability identifier (GO-2026-4394)No source code changes in LND itself; only module metadata updatedVendor describes the root build as already unaffected, limiting direct security impact on LND
This commit removes support for obsolete Tor v2 onion addresses from the Lightning Network Daemon (lnd). Tor v2 services were shut down by the Tor network in October 2021, so lnd will no longer create, accept, or dial v2 onion addresses. H…
Removal of deprecated network protocol (Tor v2) reduces attack surface and prevents futile/unsafe dials to unreachable services.Input validation added at operator boundaries (ParseAddressString, parseAddr) to reject v2 .onion addresses with a clear error.On-disk legacy key fallback now validates decrypted key type and rejects non-v3 (RSA1024) keys before passing them to Tor.
This commit fixes a bug in LND's remote-signing setup where zero-value previous transaction outputs were wrongly ignored when preparing a PSBT for a remote signer. The most concrete affected use case is BIP-322 message attestation, where t…
Functional denial-of-service in remote-signer BIP-322 workflows due to PSBT rejectionIncorrect zero-value UTXO validation caused legitimate outputs to be droppedFix removes Value check while preserving non-empty PkScript sanity check
This commit only adds new unit tests for an existing helper function in LND's RPC wallet code. It does not change any production logic, so it cannot introduce a security vulnerability or directly fix one in the code being committed. The te…
This commit removes old, unused code paths for sending Lightning payments through the main RPC server. These RPCs (SendPayment, SendPaymentSync, SendToRoute, SendToRouteSync) were already deleted from the service definition in a prior chan…
Removal of deprecated RPC handlers and macaroon permissionsDeletion of dead payment-dispatch helper codeNo new input parsing, network exposure, or privilege changes introduced
This commit removes three old, deprecated payment RPC methods (SendPayment, SendToRoute, and TrackPayment) from the LND Lightning node's router service. These methods were already replaced by newer V2 versions and were only thin wrappers a…
Removal of deprecated RPC surface reduces attack surfaceMacaroon permission entries for removed methods are deletedNo new code paths or logic added
This change closes a denial-of-service weakness in LND's onion-message forwarding. Previously, an attacker could create unlimited free peer identities and burn through the global byte-budget reserved for onion messages, starving real peers…
Adds a Sybil-resistance gate requiring funded, non-pending channels for onion message ingressChannel gate runs before per-peer and global rate limiters, preventing no-channel peers from consuming any token budgetIntroduces atomic shadow counter for O(1) hot-path checks on every incoming onion packet
This commit only updates test data in a JSON file used for automated tests of Lightning's new taproot channel features. It adds secret nonce values and corrects public nonce values so the test vectors match the expected commitment transact…
No production code modifiedTest-only JSON fixture updateNonce values are part of test vectors, not live secrets
This change adds a hidden switch that lets developers plug in a custom random source when creating MuSig2 signing nonces, mainly so tests can produce exactly the same signatures every time. In normal operation the switch is left empty, so …
New optional custom random source for MuSig2 nonce generationDefault call sites explicitly pass empty option, preserving CSPRNG behaviorCode comments state the option is intended only for reproducible test vectors
This commit only adds new test code and a JSON file of expected test outputs for Taproot Lightning channels. It does not change any production logic, network behavior, or wallet handling. There is no security issue in the commit itself.
This commit only adds a new test to the project's test suite. It does not change any production code, user-facing behavior, or network protocol. The new test cryptographically checks that example transactions in the project's test data car…
Adds independent cryptographic signature verification for test vectorsUses txscript.NewEngine with StandardVerifyFlags to mirror on-chain validationVerifies both the commitment transaction and each HTLC resolution transaction
lnwallet/rpcwallet: accept zero-value WitnessUtxo entries in remote-sign prep
Before forwarding a SignOutputRaw request to the remote signer instance, remoteSign rebuilds a PSBT from the unsigned transaction and annotates every input with a WitnessUtxo (so the downstream walletkit.SignPsbt call accepts it — taproot sighash computation requires the prev output of every input, not just the one being signed).
For non-signed inputs the prep stage first asks the watch-only wallet about the outpoint via FetchOutpointInfo, then — when the wallet does not own or track the outpoint — falls back to the sign descriptor's PrevOutputFetcher. The fallback previously required `utxo.Value != 0`, which silently dropped legitimate zero-value entries on the floor and left the corresponding PSBT input bare.
The walletkit.SignPsbt entry point on the remote signer then rejected the PSBT with "input (index=N) doesn't specify any UTXO info" because input N had neither a WitnessUtxo nor a NonWitnessUtxo annotation.
BIP-322 (signing virtual transactions for message attestation) is the canonical hitter: its to_spend output is mandated by the BIP to be exactly value=0 with the message commitment as pk_script, and that output is referenced as input 0 of every BIP-322 to_sign transaction. Any caller that drives a BIP-322 sign through a remote-signer LND deployment was failing for this reason.
The validation we actually want is that the fetched prev output is representable as a usable WitnessUtxo: non-nil and with a non-empty pk_script. Drop the Value check; the zero-value case is well-formed and the resulting PSBT input will serialize cleanly. The fetched-but- empty-pk_script case continues to be rejected (a WitnessUtxo with empty PkScript is malformed at PSBT serialization), and the warning log when no fallback resolves the outpoint is preserved verbatim.
Lift the WitnessUtxo-population loop out of remoteSign into a package-level helper so the resolution policy is unit-testable without spinning up a real wallet + remote signer pair. The helper takes a fetchOutpointInfoFn callback that mirrors lnwallet.WalletController.FetchOutpointInfo. No behavior change for the wallet-owns-it path or the no-fallback path.
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 boundaryupdate trustsigning or wallet path
AI analysis · Low 43/100
This commit fixes a bug in LND's remote-signing setup where zero-value previous transaction outputs were wrongly ignored when preparing a PSBT for a remote signer. The most concrete affected use case is BIP-322 message attestation, where the protocol requires a zero-value output. Because of the bug, the remote signer would refuse to sign, causing a functional failure rather than a loss of funds. The patch removes the mistaken zero-value check and adds a unit-testable helper function.
Remove the SendPayment, SendToRoute, and TrackPayment shim methods from router_server_deprecated.go that delegated to their V2 counterparts. Remove their macaroon permission entries from router_server.go and the now-unused legacyTrackPaymentServer wrapper.
73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Why it was queued
credential or privilege state
AI analysis · Low 37/100
This commit removes three old, deprecated payment RPC methods (SendPayment, SendToRoute, and TrackPayment) from the LND Lightning node's router service. These methods were already replaced by newer V2 versions and were only thin wrappers around them. Removing them reduces the amount of code that could contain bugs and removes their access permissions, but it may also break older client software that still calls these methods.
lnrpc: remove deprecated Send* RPC server implementations
Remove handler implementations and macaroon permission entries for the now-deleted lnrpc RPCs: SendPayment, SendPaymentSync, SendToRoute, and SendToRouteSync.
Also remove the dead payment infrastructure that was exclusively used by these handlers: paymentStream, rpcPaymentRequest, rpcPaymentIntent, extractPaymentIntent, dispatchPaymentIntent, sendPayment, and sendPaymentSync.
73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Why it was queued
credential or privilege state
AI analysis · Informational 15/100
This commit removes old, unused code paths for sending Lightning payments through the main RPC server. These RPCs (SendPayment, SendPaymentSync, SendToRoute, SendToRouteSync) were already deleted from the service definition in a prior change, so this patch only cleans up the leftover server-side implementations and their macaroon permissions. There is no security vulnerability here; it is routine code deletion of dead functionality.
Security candidatedocs: add v0.21.0 RC testing guides for humans and agentsby saubyk · 2d0187c6 · May 13, 2026 · 12 filesMessage 95 · StrongTriage 0Details
Commit message · saubyk
docs: add v0.21.0 RC testing guides for humans and agents
Adds docs/testing-guides/v0.21.0/ with a per-feature guide for the v0.21.0-beta.rc1 release. Each guide follows a fixed template (prereqs, setup, scenarios with concrete pass/fail signals, failure investigation) so RC testers and automated agents can work through them predictably.
This is a first draft intended for community review on the PR. payment-sql-migration.md carries a TBD callout for the SkipNativeSQLMigration rescue-path behavior, pending developer confirmation.
95/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Uses a recognizable type or scope✓ Provides detailed explanatory context✓ Mentions testing or verification
lntest: pin pre-v30 mempool policy defaults in itest bitcoind
Bitcoind v30 lowered the default minrelaytxfee and incrementalrelayfee from 1000 sat/kvB (1 sat/vB) to 100 sat/kvB. The itest suite was written against the old defaults and the lower values cascade into:
- integer sat/vByte assertions losing precision below 1 sat/vB, and - RBF bump thresholds that alter sweeper/bumpfee replacement timing.
Pin the old defaults in the itest bitcoind backend so the existing tests keep passing without per-test adaptation. Running against the new defaults is still worth doing, but that is a separate exercise that should not be bundled with the v30 version bump.
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
access control
Security candidatepeer: gate onion message ingress on having an open channelby Olaoluwa Osuntokun · c0827e8e · Apr 15, 2026 · 9 filesMessage 95 · StrongHigh 76Details
Commit message · Olaoluwa Osuntokun
peer: gate onion message ingress on having an open channel
Onion message forwarding is an unpaid side channel. Without any peer qualification the byte-bucket limiters added in the previous commits are our only defense against a Sybil attacker: an attacker that can cheaply spin up N identities and burn a full per-peer byte budget on each one saturates the global bucket and converts the aggregate cap into a service-denial primitive against legitimate channel peers. This was raised on PR review — the per-peer cap is good, but the global cap on its own is a Sybil multiplier if peer identity is free. The proper fix is to make new identities cost real capital, which is what requiring a funded channel does.
This commit adds a channel-presence gate as the first check in allowOnionMessage, ahead of both the per-peer and the global rate limiters. Messages from peers that do not have at least one fully open channel with us are dropped with a new dropReasonNoChannel sentinel and never allocate any rate limiter state — the gate runs before either limiter is consulted, so no-channel peers cannot burn tokens on any bucket. Pending channels are deliberately excluded from the check: they are represented as nil values in the activeChannels map, are cheap to open and prone to getting stuck, and so do not provide the capital-cost guarantee the Sybil defense depends on. Existing Brontide cleanup paths (StopOnionActorIfExists, OnionPeerLimiter.Forget) already handle teardown on peer disconnect; nothing new is needed there because the gate keeps no-channel peers from ever allocating per-peer state in the first place.
For the hot path we cannot afford to iterate the activeChannels registry on every incoming onion message, so Brontide now carries a numActiveChans atomic.Int32 that shadows the count of non-pending entries in activeChannels. hasActiveChannels is a single atomic Load and is therefore O(1). The counter is maintained in lockstep with activeChannels at every mutation site: loadActiveChannels increments it as it populates the registry during Start(); addActiveChannel uses a new lnutils.SyncMap.Swap method (a thin typed wrapper around sync.Map.Swap) to atomically replace any prior entry so that both brand-new channels and pending-to-active promotions bump the counter by exactly one; WipeChannel and handleRemovePendingChannel both use LoadAndDelete so they can inspect the prior value and only decrement when the removed entry was non-nil. Under race, this keeps the counter and the map consistent even when RPC WipeChannel races with the channelManager goroutine.
The accompanying unit tests cover: the no-channel drop path at the allowOnionMessage level, asserting that neither the global stub counter nor the per-peer limiter's dropped counter move when the gate fires; the subsequent channel-gained path on the same peer, asserting the same message is accepted once hasChannel flips; and a focused Brontide-level test that walks the counter through initial emptiness, a pending-only state (counter must stay at zero), a pending-to-active promotion via direct Store + Add, the pending delete path through handleRemovePendingChannel (must not underflow), and the active delete path through LoadAndDelete + Add(-1) that WipeChannel uses internally. Running with -race confirms the Swap/LoadAndDelete patterns keep the counter and the map in sync under concurrent access.
95/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode✓ Mentions testing or verification
This change closes a denial-of-service weakness in LND's onion-message forwarding. Previously, an attacker could create unlimited free peer identities and burn through the global byte-budget reserved for onion messages, starving real peers. The patch now requires a peer to share at least one funded, fully open Lightning channel before any onion message is accepted, so each attacker identity must lock up real bitcoin. It also adds a fast O(1) atomic counter so this check does not slow down every incoming message.
The existing per-peer actor mailbox (capacity 50, RED from depth 40) only bounds in-flight queue depth. It does not cap throughput: a peer that drains its actor quickly can saturate our Sphinx unwrap CPU, replay-DB writes, and outbound forwarding bandwidth without ever tripping RED. At spec-max onion message sizes (~32 KiB per sphinx packet) a single well-behaved-draining peer is enough to push multiple Mbps of unpaid forwarded traffic through us, and aggregate fan-in from many peers multiplies that into tens of Mbps — an amount of bandwidth that is very much out of proportion for a side channel on a payment routing node.
This commit adds the building blocks for two token-bucket limiters that will be wired into the onion message ingress path in a follow-up commit: a process-wide global limiter and a per-peer registry. Both drop (rather than wait) on over-limit so that a hostile peer cannot grow our goroutine or memory footprint simply by sustaining above-threshold traffic. The per-peer registry keys buckets on the peer's compressed pubkey, creates them lazily, and retains them for the lifetime of the process so a peer cannot reset its burst by cycling the connection; cardinality is bounded by the live channel-peer count (the ingress call site gates on having a channel before allocating per-peer state), so no time-based GC is needed.
A minimal RateLimiter interface is introduced so that callers and tests can substitute noop or alternate implementations without reaching into x/time/rate directly, and a small countingLimiter wrapper keeps an atomic drop counter plus a one-shot first-drop flag for observability. A rate of zero (or a non-positive burst) yields a noop limiter, providing a clean "disabled" mode without branching at the call site.
On top of those, a single IngressLimiter interface composes the per-peer and global buckets behind one surface so that callers — notably the peer readHandler — only thread one object through Config and call one method per incoming onion message. Drop reasons are surfaced as sentinel errors (ErrPeerRateLimit, ErrGlobalRateLimit) wrapped in fn.Result[fn.Unit] so callers match on them with errors.Is rather than comparing free-form strings. The stock implementation encodes the load-bearing ordering — per-peer first, then global — inside AllowN so that a hostile peer whose own bucket is already empty cannot burn global tokens on every rejected attempt and starve legitimate peers.
Default constants targeting roughly ~5 Mbps worst-case ingress at spec-max message sizes are added alongside the existing mailbox defaults.
95/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode✓ Mentions testing or verification
Why it was queued
secure hardware boundary
Security candidatelnwallet: add MuSig2 secret nonces and partial sig replay to test vectorsby Olaoluwa Osuntokun · 4c225ddf · Apr 13, 2026 · 1 fileMessage 88 · StrongInformational 12Details
Commit message · Olaoluwa Osuntokun
lnwallet: add MuSig2 secret nonces and partial sig replay to test vectors
In this commit, we extend the taproot test vector generator and verifier to include MuSig2 secret nonces and a full partial signature replay test.
For the generator, we now capture the correct nonces for each commitment transaction: local's verification nonce (from LocalSession) for local's own commitment, and remote's JIT signing nonce (from RemoteSession) for the same commitment. Previously, the local nonce was incorrectly captured from the RemoteSession, which corresponds to a different commitment transaction.
The new musig2_partial_sig_replay test sub-suite verifies three properties for each test case:
1. The remote partial sig can be independently reproduced from the secret nonce and private key using musig2.Sign().
2. The local partial sig can be independently produced and verified using the local secret nonce.
3. Both partial sigs combine (via the Session API) into the exact Schnorr signature present in the commitment transaction witness.
This enables interop implementations to validate their MuSig2 signing logic against the test vectors without needing to match nonce derivation algorithms across different secp256k1 libraries.
88/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Mentions testing or verification✓ Names security-relevant behavior explicitly
Why it was queued
secret or key materialsigning boundarydefensive validationfuzzing or regression evidencenonce handlingsigning or wallet path
AI analysis · Informational 12/100
This commit only changes test code. It improves the test-vector generator for taproot channels so it records the correct MuSig2 secret nonces, and adds a new test that replays the signing process to confirm the produced signatures match the ones stored in the test vectors. There is no change to production wallet or signing logic, so it does not introduce or fix a live security vulnerability.
multi: add custom nonce rand support to MuSig2 sessions
In this commit, we add the ability to inject a custom random source for generating JIT (Just-In-Time) signing nonces in MuSig2 sessions. By default, MuSig2 signing nonces are generated using crypto/rand, which makes signatures non-deterministic across runs. For test vector generation, we need fully reproducible signatures from a fixed seed.
A new `customNonceRand` field is threaded through `MusigSession`, `MusigSessionCfg`, `MusigPairSession`, and exposed via the `WithCustomSigningRand` channel option. When set, the custom reader is passed to `musig2.WithCustomRand()` during JIT nonce generation in `SignCommit`. All existing callers pass `fn.None[io.Reader]()` to preserve the current behavior of using the system CSPRNG.
88/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Mentions testing or verification✓ Names security-relevant behavior explicitly
Why it was queued
entropy or randomnesssigning boundaryfuzzing or regression evidencesigning or wallet path
AI analysis · Informational 19/100
This change adds a hidden switch that lets developers plug in a custom random source when creating MuSig2 signing nonces, mainly so tests can produce exactly the same signatures every time. In normal operation the switch is left empty, so the code still uses the operating system's cryptographic random generator. The patch itself is a test-infrastructure feature, not a fix for an active security bug, but any future misuse of the switch could weaken signature security.
lnwallet: regenerate test vectors with BIP-340 HTLC signatures
Regenerate the test vector JSON with HTLC second-level transaction signatures that use BIP-340 standard nonce derivation (zero auxrand) instead of RFC6979. This makes the HTLC signatures reproducible across different Schnorr implementations. The commitment transaction MuSig2 signatures are unchanged.
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
signing boundaryfuzzing or regression evidencesigning or wallet path
AI analysis · Informational 15/100
This commit only updates test data in a single JSON file. It changes the example signatures used in automated tests so they are generated with a standard BIP-340 nonce method instead of an older RFC6979 method. No production wallet code, protocol logic, or user-facing behavior is changed. There is no security vulnerability here.
Security candidatelnwallet: add secret nonce stashing to MusigSession for test vectorsby Olaoluwa Osuntokun · 2148445c · Apr 13, 2026 · 1 fileMessage 83 · StrongInformational 18Details
Commit message · Olaoluwa Osuntokun
lnwallet: add secret nonce stashing to MusigSession for test vectors
In this commit, we add the ability for MusigSession to capture and expose the raw 97-byte MuSig2 secret nonce generated during JIT signing nonce creation. This is gated behind the customNonceRand option, so it only activates in test vector generation mode.
The stashed secret nonce is consumed on read (cleared after access) to prevent accidental nonce reuse. This enables interop test vectors to include the raw secret nonces, allowing other implementations to replay the MuSig2 signing process without needing to match the exact nonce derivation algorithm used by btcd's musig2 library.
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
signing boundaryfuzzing or regression evidencenonce handlingsigning or wallet path
AI analysis · Informational 18/100
This commit adds a test-only feature that lets LND temporarily save the secret random number (nonce) used in MuSig2 signing when running in a special test-vector generation mode. The saved value is automatically erased after one read to prevent accidental reuse. There is no indication this feature is active in normal production code, and the change is explicitly described as being for interoperability test vectors only.
lnwallet: fix HTLC sig-to-transaction mapping in test vector generator
In this commit, we fix two interrelated bugs in the way HTLC signatures are associated with their corresponding second-level transactions in the taproot test vector generator.
The first issue was that HtlcSigs are sorted by BIP 69 output index (matching the commitment transaction's output ordering), but the old code was assigning signatures using the iteration order of incoming HTLCs followed by outgoing HTLCs. This meant timeout transaction signatures were getting paired with success transactions and vice versa whenever the output ordering didn't happen to match the incoming-first iteration order. This is the root cause of the invalid HTLC-timeout signatures that eclair reported when cross-validating.
We now collect all HTLC entries (both incoming and outgoing) into a single slice, sort them by their commitment output index, then zip them against the HtlcSigs array so each signature lines up with the correct second-level transaction.
The second issue was in the HTLC-success preimage extraction path. The old code read the witness script from index [4] (the control block) and used a hardcoded byte offset of 69 to locate the payment hash, then wrote the preimage into index [3] (overwriting the script). The correct taproot witness layout is [remoteSig, localSig, preimage, script, controlBlock], so the script lives at [3] and the preimage slot is [2]. We now use `txscript.ScriptTokenizer` to walk the script opcodes and find OP_HASH160 followed by the 20-byte push data, which is far more robust than relying on fragile byte offsets that break if the script template ever changes.
100/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode✓ Mentions testing or verification✓ Names security-relevant behavior explicitly
Why it was queued
signing boundaryfuzzing or regression evidencesigning or wallet path
AI analysis · Informational 24/100
This commit fixes bugs in a test-data generator used by LND, not in the live Lightning node software itself. The generator produces sample HTLC (multi-hop payment) resolution transactions and signatures that other implementations use to cross-check compatibility. The old code paired signatures with the wrong transactions when HTLC outputs were not ordered 'incoming first,' and it also read preimages from the wrong witness slot using a hardcoded byte offset. These bugs caused invalid test vectors, which another implementation (Eclair) noticed during cross-validation. The fix only changes test code, so it does not create or close a real attack path against running LND nodes.
lnwallet: add 3rd-party signature verification for taproot test vectors
In this commit, we add a `signature_verification` sub-test to the taproot test vector verifier that performs full script execution against both the commitment transaction and all HTLC resolution transactions.
This uses `txscript.NewEngine` to execute the taproot witness programs exactly as a Bitcoin node would, providing an independent check that all signatures in the test vectors are cryptographically valid. For the commitment transaction, we verify its witness against the funding output pkScript. For each HTLC resolution transaction, we verify its witness against the corresponding commitment output it spends.
This catches issues that the structural comparison tests (hex matching) cannot: for instance, a transaction can have the correct structure but carry an invalid signature if the sighash was computed over the wrong prevout or if the wrong key was used for signing. Running the full script engine also validates the control block, the tap leaf hash, and the overall taproot spend path.
88/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Mentions testing or verification✓ Names security-relevant behavior explicitly
Why it was queued
signing boundarydefensive validationfuzzing or regression evidencesigning or wallet path
AI analysis · Informational 12/100
This commit only adds a new test to the project's test suite. It does not change any production code, user-facing behavior, or network protocol. The new test cryptographically checks that example transactions in the project's test data carry valid Bitcoin signatures. It is a defensive quality improvement, not a fix for a known bug or vulnerability.
Security candidatelnwallet: use BIP-340 nonce derivation for HTLC sigs in test vectorsby Olaoluwa Osuntokun · 63450b85 · Apr 13, 2026 · 1 fileMessage 88 · StrongInformational 19Details
Commit message · Olaoluwa Osuntokun
lnwallet: use BIP-340 nonce derivation for HTLC sigs in test vectors
btcd's schnorr.Sign defaults to RFC6979 nonce derivation, while libsecp256k1 (used by eclair, CLN, etc) uses BIP-340's standard nonce derivation with zero auxrand. Both are deterministic but produce different signatures for the same key and message, causing HTLC signature mismatches in interop test vectors.
This commit introduces a bip340Signer wrapper that overrides SignOutputRaw for taproot script path spends to use schnorr.CustomNonce([32]byte{}) — matching BIP-340 deterministic signing behavior. The wrapper is only used in the test vector generator; production signing paths are unchanged.
Note that MuSig2 commitment signatures were already using BIP-340 nonces internally (via the musig2.Sign path), so only the HTLC second-level transaction signatures were affected.
88/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Mentions testing or verification✓ Names security-relevant behavior explicitly
Why it was queued
signing boundaryfuzzing or regression evidencesigning or wallet path
AI analysis · Informational 19/100
This commit changes only a test file in LND. It makes the test-vector generator produce HTLC signatures using the same nonce math as other Lightning implementations (Eclair, Core Lightning), so cross-implementation test vectors match. Production signing code is not touched, so real user funds or network behavior are unaffected. There is no security vulnerability being fixed here; it is a test-infrastructure consistency change.
Regenerate `test_vectors_taproot.json` to reflect the corrected test vector generator. Changes include actual 32-byte MuSig2 partial signatures (replacing the dummy 8-byte DER stubs), 66-byte public nonces for both local and remote parties, corrected HTLC sig-to- transaction mapping sorted by BIP 69 output index, proper HTLC-success witness layout with preimage in the correct witness slot, and the updated trimming test case which now trims 3 of the 5 test HTLCs below the 2500 sat dust limit (down from 5 HTLC outputs to 2).
78/100 · AdequateMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Mentions testing or verification
Why it was queued
signing boundaryfuzzing or regression evidencesigning or wallet path
AI analysis · Informational 18/100
This commit only updates a single JSON file of test vectors for taproot Lightning channels. It replaces placeholder signature data with realistic values, fixes the order of test transactions, and adjusts a dust-limit test case. There is no change to production wallet or node code, so it does not directly affect live funds or network security. It is essentially a correction to the project's test fixtures.
lnwallet: regenerate taproot test vectors with secret nonces
Regenerate the test vectors JSON to include local_sec_nonce and remote_sec_nonce fields alongside the existing public nonces. The local nonce fields now correctly correspond to local's verification nonce for their own commitment transaction, matching the commitment tx stored in the test vector.
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
defensive validationfuzzing or regression evidencenonce handlingsigning or wallet path
AI analysis · Informational 12/100
This commit only updates test data in a JSON file used for automated tests of Lightning's new taproot channel features. It adds secret nonce values and corrects public nonce values so the test vectors match the expected commitment transactions. There is no change to production wallet or network code, so it does not introduce a security vulnerability or fix one in running software.
Security candidatelnwallet: emit actual MuSig2 partial sigs and nonces in test vectorsby Olaoluwa Osuntokun · fa97946f · Apr 13, 2026 · 1 fileMessage 88 · StrongInformational 18Details
Commit message · Olaoluwa Osuntokun
lnwallet: emit actual MuSig2 partial sigs and nonces in test vectors
In this commit, we fix the taproot test vector generator to capture and emit the real MuSig2 partial signatures and public nonces rather than the dummy `CommitSig` value which is zeroed out for taproot channels.
Previously, the generator was reading from `CommitSig.ToSignatureBytes()` which yielded a minimal DER encoding of `(0, 0)` (the 8-byte string `3006020100020100`). For taproot channels the actual signature lives in the `PartialSig` field of the `CommitSigs` struct, which carries both the 32-byte partial sig scalar and the 66-byte compressed public nonce needed by the verifier to reconstruct the combined signature.
We now unwrap the `PartialSig` from both the local and remote commitment signatures, extract the nonce and sig bytes, and include `local_nonce` and `remote_nonce` fields alongside `remote_partial_sig` in the emitted JSON. This gives other implementations (eclair, CLN, etc.) all the material they need to independently verify commitment transaction signatures using their own MuSig2 libraries.
88/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Mentions testing or verification✓ Names security-relevant behavior explicitly
Why it was queued
signing boundaryfuzzing or regression evidencesigning or wallet path
AI analysis · Informational 18/100
This commit fixes a test-data generator used by the LND Lightning node. Previously, the generator wrote a placeholder zero-value signature into its JSON test vectors for Taproot channels. Now it writes the real partial signature and public nonce values that other Lightning implementations need to independently check those test vectors. This is a test tooling fix, not a live security bug in production code.
lnwallet: add taproot channel test vector generator
In this commit, we add a test vector generator and verifier for taproot channel constructions. All vectors are derived deterministically from a single 32-byte seed using SHA256(seed || label) for key derivation, ensuring any implementation can reproduce them independently.
The generator covers two areas:
Script vectors decompose the full tapscript trees for every output type: funding (MuSig2 aggregated key), to_local (delay + revocation leaves), to_remote (1-block CSV leaf), anchors (OP_16 OP_CSV), offered/accepted HTLCs on both local and remote commits, and second-level HTLC transactions. Each entry captures the raw leaf scripts, leaf hashes, tapscript root, internal key, output key, and pkScript.
Transaction vectors produce full serialized commitment transactions and HTLC resolution transactions for three scenarios: a simple commitment with no HTLCs, a commitment with five untrimmed HTLCs, and the same HTLCs at a higher fee rate causing some to be trimmed.
To generate: go test -run TestTaprootVectors ./lnwallet/ -args -generate-taproot-vectors To verify: go test -run TestTaprootVectors ./lnwallet/
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
secret or key materialfuzzing or regression evidencesigning or wallet path
AI analysis · Informational 15/100
This commit only adds new test code and a JSON file of expected test outputs for Taproot Lightning channels. It does not change any production logic, network behavior, or wallet handling. There is no security issue in the commit itself.
input: add production taproot HTLC succeed input constructor
This commit adds MakeTaprootHtlcSucceedInputFinal, a new input constructor specifically for creating HTLC success inputs that use production taproot witness types. This function parallels the existing MakeTaprootHtlcSucceedInput but creates inputs with the TaprootHtlcAcceptedRemoteSuccessFinal witness type instead of the staging variant.
The new constructor follows the same pattern and signature as its staging counterpart, ensuring consistency in the input creation API. This allows contract resolvers to create the appropriate input type based on whether they are handling a staging or production taproot channel, ensuring that the correct witness generation logic is applied during transaction creation.
This addition provides the necessary infrastructure for production taproot channels to properly construct inputs for sweeping HTLC outputs on remote commitment transactions with the optimized script structure.
78/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Names security-relevant behavior explicitly
actor: add CompleteWith and AwaitFuture generic package-level helpers
In this commit, we add two package-level generic helpers to the actor module as part of the broader chan error -> Future[error] migration in the discovery package.
CompleteWith[T](p Promise[T], val T) is a one-liner convenience wrapper over p.Complete(fn.Ok(val)). It lets callers complete a promise with a plain value without constructing an fn.Result inline, which cuts noise at every completion site.
AwaitFuture[T](ctx, f Future[T]) (T, error) provides the symmetric receive side: it blocks until the future resolves or the context is cancelled and returns the value and any context error unpacked from the fn.Result, matching the (val, err) convention callers expect.
Both functions are deliberately thin (no policy, no timeout, no new state) so they compose freely with higher-level helpers built on top, e.g. discovery.AwaitGossipResult.
go.mod is updated to pin the actor module via a local replace directive so the rest of the lnd module picks up these additions without waiting for a tagged release.
73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Why it was queued
access control
Security candidategraph/db: add gossip version parameter to FilterKnownChanIDsby Elle Mouton · 12f8e509 · Apr 9, 2026 · 5 filesMessage 78 · AdequateTriage 18Details
Commit message · Elle Mouton
graph/db: add gossip version parameter to FilterKnownChanIDs
Add an explicit lnwire.GossipVersion parameter to FilterKnownChanIDs on the Store interface, SQLStore, KVStore, and ChannelGraph. Since FilterKnownChanIDs is always called from a version-scoped ChanSeries context, a single version parameter is cleaner than per-item version reads. A convenience wrapper on VersionedGraph preserves the existing ChanSeries call-site signature by threading c.v automatically.
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
signing boundary
Security candidateci: use GITHUB_TOKEN instead of PAT for PR severity workflowby ziggie · 77c566f2 · Apr 8, 2026 · 1 fileMessage 97 · StrongTriage 0Details
Commit message · ziggie
ci: use GITHUB_TOKEN instead of PAT for PR severity workflow
The PR severity classifier only needs to run `gh pr view`, `gh pr edit` (labels), and `gh pr comment`. All three operations are fully covered by the built-in GITHUB_TOKEN given the existing permissions block:
The workflow uses `pull_request_target`, which runs in the base repo context, so GITHUB_TOKEN has write access even for fork PRs.
Inspection of the claude-code-action@v1 source confirmed that the only internal call that would require `contents: write` is branch deletion, which is never exercised here because Claude's tools are locked down to `gh pr view/edit/comment` via --allowedTools.
This removes the dependency on the PR_SEVERITY_BOT_TOKEN PAT secret.
97/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Uses a recognizable type or scope✓ Provides detailed explanatory context✓ Explains rationale or failure mode
Why it was queued
credential or privilege statedocumentation-only discount
graph/db: convert TestLightningNodeSigVerification to versioned test
Rename to testLightningNodeSigVerification and add it to the versionedTests table so it runs against both v1 and v2. The signing step is version-specific (ECDSA for v1, Schnorr for v2) while the verification path is shared.
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
signing boundarydefensive validation
AI analysis · Informational 15/100
This commit only changes a test file. It renames an existing test and makes it run against two versions of the software's gossip protocol, adding Schnorr signature coverage for the newer version. There is no change to production code, so it does not introduce or fix a security vulnerability in the running software.
lnwire: validate MuSig2 nonces in LocalNoncesData decode
Validate each nonce in decodeLocalNoncesData with ValidateMusig2Nonce to reject malformed entries.
65/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides an explanatory body
Why it was queued
defensive validationnonce handling
AI analysis · Moderate 59/100
This change adds a safety check when LND reads stored MuSig2 cryptographic nonces from disk or network data. Previously, a malformed or all-zero nonce could be loaded silently; now the decoder rejects it. MuSig2 nonces are used in multi-signature Bitcoin transactions for the Lightning Network, so bad nonces could in theory lead to failed channel operations or, in worst-case cryptographic scenarios, weaken security guarantees.
Security candidategraph/db: add v2 block-height path for NodeUpdatesInHorizonby Elle Mouton · c14a79c0 · Mar 31, 2026 · 5 filesMessage 78 · AdequateTriage 18Details
Commit message · Elle Mouton
graph/db: add v2 block-height path for NodeUpdatesInHorizon
Add GetNodesByBlockHeightRange SQL query and wire it into SQLStore.nodeUpdatesInHorizonV2. This mirrors the existing v1 time-based query but filters on (version, block_height) instead of last_update, using the same [start, end) exclusive-end semantics and (block_height, pub_key) compound cursor pagination.
The public-node filter for v2 checks for channels with a non-empty channel announcement signature (c.signature), matching the v2 protocol's public channel indicator.
78/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Names security-relevant behavior explicitly