LL
← All projectsLightning Labs

LND

Go implementation of a complete Lightning Network node.

BitcoinLightning NetworkNormal
Repository coverage

1235 commits in the local evidence base

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.

116security candidates168second-pass queue194AI analyses
76commits · 30 days
165commits · 60 days
824commits · 180 days
1231commits · 365 days
Backfill bands
Aug 5 → Feb 6405 seen5 candidatesComplete
Feb 6 → Jun 6665 seen28 candidatesComplete
Jun 6 → Jul 689 seen4 candidatesComplete
Jul 6 → Aug 569 seen0 candidatesComplete
Commit communication

Does the history explain itself?

Message quality measures whether a commit identifies its scope, purpose, rationale, testing, and supporting references. It does not change the security-severity score.

67/100 average clarity
279Strong · 80–100
559Adequate · 60–79
366Thin · 40–59
31Opaque · 0–39
1security candidate with opaque commit messaging
Read the scoring rubric →
Developer activity

Who is changing the project?

Public Git author strings; identities are not independently verified.

DeveloperCommitsCandidatesAnalyzedHigh riskMessage avg.
Olaoluwa Osuntokun1994066274
Elle Mouton2673141067
ziggie4081525064
Erick Cestari26711070
bitromortac4658067
yyforyongyu5533065
saubyk1522070
Oli723057
Suheb322075
elnosh322071
George Tsagkarelis32114066
Gijs van Dam2612071
Analysis record

Published AI watches

Last scanned 38 minutes ago

Moderate 63 AI analysisMessage 58 · Thin
LL Lightning LabsLND BitcoinLightning Network

Merge pull request #11024 from ziggie1984/invoices-update-validation

This commit tightens how LND processes invoice payments, especially for newer multi-path (MPP) and AMP invoices, keysend payments, and replayed payments. It adds checks that ensure the right payment preimage is used for each invoice type a…

Preimage validation added for AMP and regular invoice replaysAMP invoices forced into MPP update path, preventing legacy-path processingLegacy settlement now fails when invoice-level preimage is missing
61f3b5a7by ziggieXXX+482−114 files
No security note in commit
Moderate 59 AI analysisMessage 35 · Opaque
LL Lightning LabsLND BitcoinLightning Network

invoices: refine update handling

This commit tightens how LND handles invoice payment updates, especially for newer 'AMP' invoices and old-style 'keysend' payments. It adds checks so that the wrong kind of payment cannot be processed against the wrong kind of invoice, and…

Added preimage/hash mismatch checks for both regular and AMP invoice replaysAMP records now require an MPP payload, preventing AMP processing on the legacy pathLegacy path now rejects AMP invoices and invoices missing invoice-level preimages
6be6350eby ziggie+476−113 files
No security note in commit
Informational 21 AI analysisMessage 73 · Adequate
LL Lightning LabsLND BitcoinLightning Network

bolt12: add InvoiceError onion message replies

This commit adds support in LND for a new Lightning protocol message called InvoiceError. It is used to politely tell another node why their payment invoice or invoice request was rejected, sent privately through an onion-routed message. T…

New unsigned onion message type added with no cryptographic signature or bech32 formWriter-side validation prevents empty or non-UTF-8 error strings and disallowed suggested_value without erroneous_fieldReader-side BOLT 1 must-understand rule enforced: unknown even TLVs rejected, unknown odd TLVs tolerated
e279cdf1by bitromortac+567−04 files
No security note in commit
Low 36 AI analysisMessage 73 · Adequate
LL Lightning LabsLND BitcoinLightning Network

bolt12: validate Invoice messages

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
e0f04f17by bitromortac+1642−74 files
No security note in commit
Informational 12 AI analysisMessage 73 · Adequate
LL Lightning LabsLND BitcoinLightning Network

bolt12: add Invoice struct and TLV codec

This commit adds new code to support BOLT 12 invoices in the LND Lightning node. It introduces a data structure, encoding/decoding logic, and helper functions to filter fallback addresses and blinded payment paths. There is no bug fix or s…

efbeef58by bitromortac+777−02 files
No security note in commit
Informational 15 AI analysisMessage 80 · Strong
LL Lightning LabsLND BitcoinLightning Network

ci: split issue dedupe into find and post jobs

This commit is a hardening and refactoring change to a GitHub Actions workflow that detects duplicate issues. It splits the workflow into two jobs: one that only reads issue data and uses an AI model to find duplicates, and a second that o…

Principle of least privilege: AI/model job no longer holds issues:write or id-token:writeAction dependency pinned to full commit SHA instead of mutable tagpersist-credentials: false set on checkout steps
d1ea8687by Olaoluwa Osuntokun+148−71 file
No security note in commit
Informational 15 AI analysisMessage 85 · Strong
LL Lightning LabsLND BitcoinLightning Network

ci: split PR severity workflow into classify and apply jobs

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
05c62527by Olaoluwa Osuntokun+424−593 files
Vendor flagged security relevance
Informational 21 AI analysisMessage 68 · Adequate
LL Lightning LabsLND BitcoinLightning Network

github: bump gateway code-review to v0.5.0

This commit updates a GitHub Actions workflow for an optional code-review bot called 'gateway' from version 0.4.4 to 0.5.0. It adds support for replying to inline review comments (not just regular PR comments) and pins the new action and r…

Workflow-only change with no modifications to LND application codeAction and runtime pinned to immutable commit SHAs (supply-chain mitigation)New pull_request_review_comment trigger added; commit message asserts same fork-PR secret safety as issue_comment
447703a4by saubyk+20−61 file
No security note in commit
Informational 15 AI analysisMessage 78 · Adequate
LL Lightning LabsLND BitcoinLightning Network

lnwallet: use channel state open channel

This commit is a straightforward internal code cleanup: it changes the lnwallet package to use the OpenChannel type from a dedicated chanstate package instead of getting it indirectly through the channeldb package. There is no change to us…

fa31c564by ziggie+59−469 files
No security note in commit
Informational 15 AI analysisMessage 68 · Adequate
LL Lightning LabsLND BitcoinLightning Network

funding: use channel state open channel

This commit is a straightforward internal code cleanup in LND's channel-opening machinery. It swaps one internal type name (channeldb.OpenChannel) for another (chanstate.OpenChannel) across function signatures in the funding manager and it…

03daaad4by ziggie+28−272 files
No security note in commit
Informational 15 AI analysisMessage 68 · Adequate
LL Lightning LabsLND BitcoinLightning Network

chanstate: use channel type in wallet rpc

This is a small internal code cleanup in LND's wallet RPC server. It changes one helper function to use a newer internal package type (chanstate.OpenChannel) instead of an older compatibility alias (channeldb.OpenChannel). There is no user…

8a215d9eby ziggie+3−21 file
No security note in commit
Low 46 AI analysisMessage 56 · Thin
LL Lightning LabsLND BitcoinLightning Network

chanstate: fix htlc copy

This commit fixes a bug in how the Lightning Network Daemon (LND) copies payment channel data. When the program made a copy of an HTLC (a pending payment in a Lightning channel), it failed to copy several important fields and did not prope…

Incomplete deep copy of security-relevant channel stateMissing fields in HTLC clone (RHash, OnionBlob, HtlcIndex, LogIndex)Nil-slice copy bug for Signature and ExtraData
b720fd5cby ziggie+88−42 files
No security note in commit
Informational 15 AI analysisMessage 58 · Thin
LL Lightning LabsLND BitcoinLightning Network

chanstate: remove store generics

This commit is a routine internal code cleanup in the LND Lightning node software. It removes temporary generic type parameters from channel-state database interfaces and replaces them with direct references to the concrete OpenChannel typ…

68ad283dby ziggie+88−8915 files
No security note in commit
Informational 15 AI analysisMessage 78 · Adequate
LL Lightning LabsLND BitcoinLightning Network

chanstate: move taproot channel helpers

This commit is a routine code reorganization: it moves two helper functions and a constant related to Taproot channels from one internal package (channeldb) to another (chanstate), and leaves aliases in the old location so existing callers…

c065aa91by ziggie+93−632 files
No security note in commit
Informational 18 AI analysisMessage 58 · Thin
LL Lightning LabsLND BitcoinLightning Network

channeldb: derive channel packagers

This commit is a code cleanup: it removes a forwarding-package helper object from the in-memory channel state and instead creates it on demand inside database methods. There is no direct security fix or vulnerability being patched. It main…

No security-relevant keywords in commit title or messageNo changes to cryptographic operations, authentication, or network parsingRefactoring only: field removal and localized object construction
0229e0adby ziggie+47−989 files
No security note in commit
Informational 15 AI analysisMessage 68 · Adequate
LL Lightning LabsLND BitcoinLightning Network

chanstate: make store channel types generic

This commit is a pure internal code reorganization. It moves several small channel-related data types (like channel configuration, status flags, close summaries, and helper types) from the channeldb package into a new chanstate package, th…

f53d615cby ziggie+473−36518 files
No security note in commit
Low 30 AI analysisMessage 73 · Adequate
LL Lightning LabsLND BitcoinLightning Network

lnwallet+walletrpc: add SubmitPackage for v3 CPFP package relay

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
f55c0565by Elle Mouton+1019−21517 files
No security note in commit
Informational 15 AI analysisMessage 68 · Adequate
LL Lightning LabsLND BitcoinLightning Network

lncli: add wallet submitpackage command

This commit adds a new command-line tool called `lncli wallet submitpackage` that lets users hand one or more raw Bitcoin transactions to LND's wallet service so they can be submitted to the network as a group (a "package"). The change onl…

No security-relevant signals present in the diff or commit message.New CLI command is a thin wrapper around an existing RPC.No changes to validation, authentication, authorization, or network handling.
ea88a268by Elle Mouton+72−01 file
No security note in commit
Informational 15 AI analysisMessage 78 · Adequate
LL Lightning LabsLND BitcoinLightning Network

itest: add SubmitPackage integration test

This commit only adds a new integration test for an existing LND WalletKit RPC called SubmitPackage. It does not change production code, wallet logic, or network behavior. The test verifies that a zero-fee Bitcoin transaction can be accept…

47661ceaby Elle Mouton+226−03 files
No security note in commit
Low 49 AI analysisMessage 88 · Strong
LL Lightning LabsLND BitcoinLightning Network

bolt12: validate InvoiceRequest per BOLT 12 reader/writer requirements

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
8b4587b0by bitromortac+1703−53 files
No security note in commit
Repository ledger

Explore captured commits

Expand any commit for its author, full message, clarity score, changed files, triage signals, analysis, and source link.

Lower-priorityrouterrpc: isolate LSP route fee probesby yyforyongyu · 1dd09d23 · Apr 27, 2026 · 2 filesMessage 45 · ThinTriage 0Details
Commit message · yyforyongyu

routerrpc: isolate LSP route fee probes

45/100 · ThinMessage clarity
✓ Descriptive subject✓ Names a concrete action or component! No meaningful explanatory body
Lower-prioritydocs: add EstimateRouteFee release noteby yyforyongyu · 8eab1edd · Apr 27, 2026 · 1 fileMessage 57 · ThinTriage 0Details
Commit message · yyforyongyu

docs: add EstimateRouteFee release note

57/100 · ThinMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Uses a recognizable type or scope! No meaningful explanatory body
Why it was queued
documentation-only discount
AI review queuedlnwallet/test: fix flaky neutrino reorg sync timeoutby ziggie · 3cf60bd4 · Apr 27, 2026 · 1 fileMessage 95 · StrongInformational 15Details
Commit message · ziggie

lnwallet/test: fix flaky neutrino reorg sync timeout

waitForWalletSync used time.Tick inside the poll loop, leaking a new
goroutine on every iteration. Over 5 reorg cycles with ~300 polls each
this accumulated up to 1500 leaked goroutines, adding measurable system
load that made the 30s timeout too tight, especially when running against
a postgres backend where block-processing writes carry more overhead.

Fix the leak by using a single time.NewTicker (deferred Stop), and raise
the timeout to 2 minutes to give the neutrino P2P layer and the
address-manager transaction walk enough headroom under load.

Also improve the timeout error messages to identify which of the two
sync layers was stuck:
- Layer 1 (header/P2P): ChainIO.GetBestBlock height has not yet caught
up to the miner tip — neutrino is still fetching headers.
- Layer 2 (transaction walk): heights matched but IsSynced() never
returned true — the chain-sync notification or the address-manager
DB write (undo+redo on reorg) did not complete in time.

Add a detailed doc comment to waitForWalletSync explaining the three
pipeline stages (header sync, compact-filter/block fetch, transaction
walk) and why each stage is relevant, so a future timeout can be
diagnosed from the error message alone.

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
signing or wallet pathsecond-pass: security-sensitive path
AI analysis · Informational 15/100

This commit fixes a flaky automated test helper in the LND codebase. It replaces a goroutine-leaking timer with a proper reusable ticker and increases a test timeout from 30 seconds to 2 minutes so the test is less likely to fail under heavy load. It also improves error messages and adds explanatory comments. There is no user-facing security issue or production bug being fixed.

Lower-prioritycontractcourt: make breach retribution final-taproot awareby yyforyongyu · 4d374fb5 · Apr 24, 2026 · 2 filesMessage 50 · ThinTriage 0Details
Commit message · yyforyongyu

contractcourt: make breach retribution final-taproot aware

50/100 · ThinMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component! No meaningful explanatory body
Lower-priorityGitHub: bump itest bitcoind to v31by ziggie · 651e5e6e · Apr 23, 2026 · 1 fileMessage 60 · AdequateTriage 0Details
Commit message · ziggie

GitHub: bump itest bitcoind to v31

Bitcoin Core v31.0 was released on 2026-04-20. Update the CI itest
matrix to track the latest major release.

60/100 · AdequateMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Provides an explanatory body
Why it was queued
documentation-only discount
Lower-prioritytesting: allow patch versions of bitcoin coreby ziggie · 154e5076 · Apr 23, 2026 · 1 fileMessage 55 · ThinTriage 0Details
Commit message · ziggie

testing: allow patch versions of bitcoin core

55/100 · ThinMessage clarity
✓ Descriptive subject✓ Names a concrete action or component✓ Mentions testing or verification! No meaningful explanatory body
Security candidatelntest: pin pre-v30 mempool policy defaults in itest bitcoindby ziggie · 6914ea0b · Apr 23, 2026 · 1 fileMessage 83 · StrongInformational 14Details
Commit message · ziggie

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
AI analysis · Informational 14/100

This change only adjusts the settings used for internal testing of LND with a Bitcoin Core backend. It pins older Bitcoin Core fee defaults so that existing automated tests continue to produce the same results after Bitcoin Core v30 changed its defaults. It does not change production LND code, user-facing behavior, or network consensus rules, and it does not fix a security vulnerability.

Lower-prioritypeer: register the rbfCloseActor, have RPC route fee bumps to itby Olaoluwa Osuntokun · fa2d0f99 · Apr 23, 2026 · 3 filesMessage 73 · AdequateTriage 0Details
Commit message · Olaoluwa Osuntokun

peer: register the rbfCloseActor, have RPC route fee bumps to it

In this commit, we now register the rbfCloseActor when we create the rbf
chan closer state machine. Now the RPC server no longer neesd to
traverse a series of maps and pointers (rpcServer -> server -> peer ->
activeCloseMap -> rbf chan closer) to trigger a new fee bump.

Instead, it just creates the service key that it knows that the closer
can be reached at, and sends a message to it using the returned
actorRef/router. We also hide additional details re the various methods
in play, as we only care about the type of message we expect to send and
receive.

73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Lower-priorityprotofsm: implement the actor.ActorBehavior interface for StateMachineby Olaoluwa Osuntokun · ac4bc239 · Apr 23, 2026 · 2 filesMessage 73 · AdequateTriage 0Details
Commit message · Olaoluwa Osuntokun

protofsm: implement the actor.ActorBehavior interface for StateMachine

In this commit, we implement the actor.ActorBehavior interface for
StateMachine. This enables the state machine executor to be registered
as an actor, and have messages be sent to it via a unique ServiceKey
that a concrete instance will set.

73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
AI review queuedlnwallet/chancloser: create unique ServiceKey for the RBF chan closerby Olaoluwa Osuntokun · 07f54ae1 · Apr 23, 2026 · 1 fileMessage 73 · AdequateInformational 15Details
Commit message · Olaoluwa Osuntokun

lnwallet/chancloser: create unique ServiceKey for the RBF chan closer

This can be used to allow any system to send a message to the RBF chan
closer if it knows the proper service key. In the future, we can use
this to redo the msgmux.Router in terms of the new actor abstractions.

73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Why it was queued
signing or wallet pathsecond-pass: security-sensitive path
AI analysis · Informational 15/100

This commit adds a single type alias (a nickname for an existing type) in the Lightning Network Daemon's channel closer code. It does not change any behavior, fix any bug, or alter how messages are processed. It is a small code-cleanup/refactoring step to prepare for future architectural changes.

Lower-prioritypeer: create new rbfCloseActor to decouple RPC RBF close bumpsby Olaoluwa Osuntokun · 2a3ae1ef · Apr 22, 2026 · 2 filesMessage 73 · AdequateTriage 0Details
Commit message · Olaoluwa Osuntokun

peer: create new rbfCloseActor to decouple RPC RBF close bumps

In this commit, we create a new rbfCloseActor wrapper struct. This will
wrap the RPC operations to trigger a new RBF close bump within a new
actor. In the next commit, we'll now register this actor, and clean up
the call graph from the rpc server to this actor.

73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Lower-priorityscripts+GitHub: use bitcoind v30.0by ziggie · 752ad163 · Apr 22, 2026 · 1 fileMessage 45 · ThinTriage 0Details
Commit message · ziggie

scripts+GitHub: use bitcoind v30.0

45/100 · ThinMessage clarity
✓ Descriptive subject✓ Names a concrete action or component! No meaningful explanatory body
Why it was queued
documentation-only discount
Lower-prioritydocs: add release note for SIMPLE_TAPROOT_FINAL follow-upsby George Tsagkarelis · 33f623c8 · Apr 20, 2026 · 1 fileMessage 85 · StrongTriage 0Details
Commit message · George Tsagkarelis

docs: add release note for SIMPLE_TAPROOT_FINAL follow-ups

See https://github.com/lightningnetwork/lnd/pull/10763.

85/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Uses a recognizable type or scope✓ Provides an explanatory body✓ Links an issue, advisory, or supporting reference
Why it was queued
documentation-only discount
Lower-priorityserver: do not auto-enable RBF coop close for overlay channelsby George Tsagkarelis · 6d951548 · Apr 20, 2026 · 1 fileMessage 85 · StrongTriage 0Details
Commit message · George Tsagkarelis

server: do not auto-enable RBF coop close for overlay channels

An earlier commit added an auto-enable that forces RbfCoopClose=true
whenever either taproot channel flag is set. This breaks
taproot-overlay channels, because the RBF coop close state machine in
lnwallet/chancloser/rbf_coop_*.go does not integrate the AuxCloser
(or any other aux) hook that overlay channels depend on to build
aux-aware close transactions. A node that enables
--protocol.simple-taproot-overlay-chans ends up with RBF force-on and
its overlay channel closes silently fail, leaving the aux closer
unable to finalize on-chain.

Narrow the auto-enable so it only fires for TaprootChans (staging /
final taproot) and explicitly skips it when TaprootOverlayChans is set.
Operators that positively want RBF can still opt in via
--protocol.rbf-coop-close; this change only removes the forced path
that silently breaks overlay closes.

85/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode
Lower-prioritychanacceptor: map SIMPLE_TAPROOT_FINAL in rpc acceptorby George Tsagkarelis · 58231f1f · Apr 20, 2026 · 1 fileMessage 73 · AdequateTriage 0Details
Commit message · George Tsagkarelis

chanacceptor: map SIMPLE_TAPROOT_FINAL in rpc acceptor

The feature-bits-to-lnrpc-enum switch in sendAcceptRequests covered
every commitment type the RPC acceptor can be asked about, except the
production taproot variant introduced alongside the prod-taproot-chans
work. For a channel open using SimpleTaprootChannelsRequiredFinal (with
any combination of the scid-alias / zero-conf modifiers), the switch
fell through to the default branch, which logs a warning and leaves
commitmentType at its zero value -- lnrpc.CommitmentType_UNKNOWN_COMMITMENT_TYPE.
External acceptor clients then see UNKNOWN rather than the actual
commitment type and either reject or misclassify the channel.

Add the four missing cases so the new commitment type is reported to
acceptor clients correctly.

73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
Lower-prioritydocs: update contributor listby yyforyongyu · e12435ef · Apr 20, 2026 · 1 fileMessage 47 · ThinTriage 0Details
Commit message · yyforyongyu

docs: update contributor list

47/100 · ThinMessage clarity
✓ Descriptive subject✓ Uses a recognizable type or scope! No meaningful explanatory body
Why it was queued
documentation-only discount
Lower-prioritydocs: add new contributors section to contribution guidelinesby saubyk · 2e7faf0e · Apr 17, 2026 · 1 fileMessage 85 · StrongTriage 0Details
Commit message · saubyk

docs: add new contributors section to contribution guidelines

Advise new contributors to build a PR review track record before
submitting code, or to open a detailed issue when they spot a bug.

85/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Uses a recognizable type or scope✓ Provides detailed explanatory context
Why it was queued
documentation-only discount
Lower-prioritydocs: add release note for same-peer onion message cycle dropby Gijs van Dam · 84ec3cb2 · Apr 17, 2026 · 1 fileMessage 93 · StrongTriage 0Details
Commit message · Gijs van Dam

docs: add release note for same-peer onion message cycle drop

Record the onion-message same-peer cycle drop from #10754 under a new
Robustness subsection in the 0.21.0 release notes.

93/100 · StrongMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Uses a recognizable type or scope✓ Provides detailed explanatory context✓ Links an issue, advisory, or supporting reference
Why it was queued
documentation-only discount
Lower-priorityonionmessage: drop onion messages cycling back to the sending peerby Gijs van Dam · 261babcf · Apr 17, 2026 · 3 filesMessage 73 · AdequateTriage 0Details
Commit message · Gijs van Dam

onionmessage: drop onion messages cycling back to the sending peer

Block forwarding of an onion message when the resolved next hop is the
same peer that delivered it. Such a forward would immediately bounce the
message back over the very connection it arrived on, which is never
useful and can be abused to amplify traffic against a peer.

The check runs after the routing action is resolved, so both direct
next-node-ID and SCID-resolved paths are covered. A new
`ErrSamePeerCycle` is returned (and logged at warn level) when a cycle
is detected.

73/100 · AdequateMessage clarity
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context
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
Why it was queued
explicit security languagesecure hardware boundary
AI analysis · High 76/100

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.

Lower-prioritypeer: enforce onion message rate limits at ingressby Olaoluwa Osuntokun · 9cad57bf · Apr 15, 2026 · 6 filesMessage 95 · StrongTriage 0Details
Commit message · Olaoluwa Osuntokun

peer: enforce onion message rate limits at ingress

This commit plumbs the combined IngressLimiter (per-peer + global)
through peer.Config and consults it from the readHandler's
*lnwire.OnionMessage case. The decision is factored into a small
allowOnionMessage helper so that the ingress policy is directly
unit-testable without standing up a full Brontide harness. Per-peer is
checked first inside the IngressLimiter: if we consulted the global
limiter first, a peer whose own bucket was already empty would still
get to burn a global token on each attempt, letting a single hostile
peer drain the shared budget and starve legitimate peers.

peer.Config carries a single OnionLimiter field of IngressLimiter type;
the brontide readHandler calls a single AllowN per incoming onion
message and dispatches on sentinel errors via errors.Is for the
first-drop log path. Nil limiter values are treated as "disabled"
throughout, which both preserves the pre-change behavior when onion
messaging is entirely turned off and keeps the brontide test harness
from needing to construct real limiters. Per-peer bucket state is
retained across disconnect at the IngressLimiter layer so a peer
cannot cycle the connection to reset its per-peer allowance.

OnionMessage also gains a WireSize method that computes the
on-the-wire size directly from the in-memory fields (no round-trip
through Encode) so the hot ingress path can charge the right number of
byte tokens without paying for a full serialization.

The accompanying unit tests cover the nil/disabled path, the
per-peer-rejects-first ordering invariant (asserting the global
limiter is not consulted when the per-peer bucket is empty), the
global rejection path, per-peer isolation across distinct pubkeys, and
a small concurrent stress test that asserts every attempt is accounted
for as either accepted or dropped and that the total accepted count
equals the configured burst under -race. A property-based rapid test
on WireSize guards against silent divergence from WriteMessage if the
OnionMessage wire format ever gains a TLV extension.

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
Security candidateonionmessage: add token-bucket rate limiter primitivesby Olaoluwa Osuntokun · d95bcbfa · Apr 15, 2026 · 3 filesMessage 95 · StrongModerate 61Details
Commit message · Olaoluwa Osuntokun

onionmessage: add token-bucket rate limiter primitives

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
AI analysis · Moderate 61/100

This commit adds new rate-limiting building blocks for LND's onion message handling. It does not yet wire them into live message processing, so by itself it cannot stop an attack. The code is clearly preparing to fix a denial-of-service risk: a single peer (or many peers together) could currently flood a routing node with large, unpaid onion messages and consume CPU, database writes, and outbound bandwidth. The new primitives cap per-peer and total incoming onion-message bytes using token buckets, and they drop excess traffic immediately rather than queuing it.

AI review queuedlncfg+config: add tunable onion message rate limit optionsby Olaoluwa Osuntokun · 69468c32 · Apr 15, 2026 · 4 filesMessage 85 · StrongInformational 12Details
Commit message · Olaoluwa Osuntokun

lncfg+config: add tunable onion message rate limit options

In this commit we surface the onion message rate limiter thresholds as
ProtocolOptions so that operators can tune them from lnd.conf or the
command line. Four options are added — onion-msg-peer-rate,
onion-msg-peer-burst, onion-msg-global-rate, and onion-msg-global-burst —
and are documented such that a rate of zero disables the corresponding
limiter entirely. The default values are seeded from the constants added
in the previous commit via DefaultConfig, following the same pattern that
the Gossip sub-config already uses for its own rate limiter knobs.

The fields are duplicated into protocol_integration.go so that the
integration build tag sees the same surface; this mirrors how the
existing NoOnionMessagesOption and related fields are declared.

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
parser or protocol pathsecond-pass: security-sensitive path
AI analysis · Informational 12/100

This commit adds user-facing configuration options for rate-limiting onion messages in LND. It does not change any runtime behavior by itself; it only exposes knobs that operators can tune and adds startup validation to catch configuration mistakes. There is no vulnerability introduced or fixed in this diff.

AI review queuedlncfg+peer+server: add protocol.onion-msg-relay-all to bypass channel gateby Olaoluwa Osuntokun · 335b7598 · Apr 15, 2026 · 7 filesMessage 95 · StrongInformational 15Details
Commit message · Olaoluwa Osuntokun

lncfg+peer+server: add protocol.onion-msg-relay-all to bypass channel gate

Add a new protocol option, protocol.onion-msg-relay-all, that controls
whether incoming onion messages are required to come from peers with a
fully open channel. The default is false, which preserves the existing
behavior: the channel-presence gate drops messages from peers with no
channel before the rate limiters are consulted, so a new no-cost
identity cannot burn any per-peer byte budget and saturate the global
bucket. Setting the flag to true skips the gate so that onion messages
from any peer are admitted into the per-peer + global IngressLimiter
pipeline.

The flag is plumbed through ProtocolOptions in both the default and
integration build variants of lncfg/protocol*.go, threaded into the
peer subsystem as peer.Config.OnionRelayAll, and wired by the server
from s.cfg.ProtocolOptions.OnionMsgRelayAll alongside the existing
OnionLimiter field. allowOnionMessage gains a relayAll bool parameter;
the gate check becomes "if \!relayAll && \!hasChannel { drop }" so the
semantics of hasChannel stay pure — it still means "this peer has a
channel" — and the policy toggle lives entirely in the caller's
configuration rather than being spread across gate-state and flag
state.

sample-lnd.conf gains a commented-out entry for the new option with
the default value and an operator-facing note that enabling it trades
the Sybil-resistance property of the gate for reachability to peers
with whom we have no channel.

A new TestAllowOnionMessageRelayAll unit test exercises the four
(hasChannel, relayAll) combinations at the helper level, including
the key new behavior — a peer with hasChannel=false being rejected
under relayAll=false and admitted into the limiter under
relayAll=true — and the nil-limiter path under relayAll=true, which
must still accept. The existing allowOnionMessage tests were
extended with the new parameter set to false so they continue to
assert the gate semantics unchanged.

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
parser or protocol pathsecond-pass: security-sensitive path
AI analysis · Informational 15/100

This commit adds a new optional configuration flag, protocol.onion-msg-relay-all, that lets a node operator choose whether to accept onion messages only from peers that already have a payment channel (the default, safer behavior) or from any peer. It does not change the default behavior and does not fix a vulnerability; it is a feature addition that preserves the existing security gate unless explicitly disabled.

Lower-prioritydocs: add onion message rate limiting explainerby Olaoluwa Osuntokun · fc1ac5c6 · Apr 15, 2026 · 1 fileMessage 92 · StrongTriage 0Details
Commit message · Olaoluwa Osuntokun

docs: add onion message rate limiting explainer

Introduce docs/onion_message_rate_limiting.md, a prose explainer for
operators and contributors that covers the two-layer defense on the
onion message ingress path: the channel-presence gate that turns peer
identity into a capital cost, and the byte-denominated per-peer and
global token-bucket rate limiters that run behind it. The doc walks
through the adversary first so that each layer has a concrete thing
to defend against, then covers the knobs, the startup-time validation
rules, the default sizing, and the protocol.onion-msg-relay-all
escape hatch with its explicit tradeoff against Sybil resistance. A
short operator recipes section collects the common "I want to ..."
configurations so readers do not have to reconstruct them from the
principles.

No code change; documentation only.

92/100 · StrongMessage clarity
✓ 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
documentation-only discount