config_builder: wire neutrino header import config
What changed, and why it matters
This commit connects two previously-unused configuration options for Neutrino (LND's lightweight Bitcoin backend) so that users can import block and filter headers from a file or URL instead of downloading them from peers. It also loosens timestamp checks for local test networks and adds an early validation step for the Neutrino configuration. The change is a feature wiring/fix rather than a clear security patch, but it touches header validation paths that protect the wallet's view of the blockchain.
Treat as a routine feature/fix commit. Review the new Validate() implementation and the chainimport package's handling of remote URLs/local paths to ensure header sources cannot be used to bypass consensus checks on public networks. No immediate incident response is indicated.
Security signals we found
Adds early config validation to surface misconfiguration before backend initialization
Wires user-supplied header import sources into Neutrino; incorrect sources could feed a malicious or inconsistent header chain
Uses relaxed BFFastAdd validation on local test networks only, preserving contextual checks on public networks
No explicit security advisory, CVE, or researcher attribution in commit or supplied references
Evidence from the diff
The patch modifies initNeutrinoBackend in config_builder.go to: (1) call cfg.NeutrinoMode.Validate() before backend creation, (2) populate neutrino.HeadersImportConfig with BlockHeadersSource and FilterHeadersSource when both are set, and (3) use blockchain.BFFastAdd for regtest/simnet header imports while keeping BFNone for mainnet/testnet. A helper neutrinoHeadersImportValidationFlags selects the flags based on lncfg.Chain.IsLocalNetwork(). The change is additive and does not alter default behavior when the new source options are unset.
Changed components
lnd/config_builder.goNeutrino backend initializationHeadersImportConfig / chainimport header import pathInspect captured patch +39 / −0
diff --git a/config_builder.go b/config_builder.go
index 8da8b39..bcfd8ec 100644
--- a/config_builder.go
+++ b/config_builder.go
@@ -15,6 +15,7 @@ import (
"sync/atomic"
"time"
+ "github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
@@ -1739,6 +1740,11 @@ func initNeutrinoBackend(ctx context.Context, cfg *Config, chainDir string,
}
cfg.Routing.AssumeChannelValid = !cfg.NeutrinoMode.ValidateChannels
+ // Validate neutrino headers import configuration.
+ if err := cfg.NeutrinoMode.Validate(); err != nil {
+ return nil, nil, err
+ }
+
// First we'll open the database file for neutrino, creating the
// database if needed. We append the normalized network name here to
// match the behavior of btcwallet.
@@ -1840,6 +1846,24 @@ func initNeutrinoBackend(ctx context.Context, cfg *Config, chainDir string,
PersistToDisk: cfg.NeutrinoMode.PersistFilters,
}
+ // Configure headers import if both sources are specified. The
+ // chainimport package handles both HTTP URLs and local file paths
+ // transparently based on the source string prefix.
+ blockHdrSrc := cfg.NeutrinoMode.BlockHeadersSource
+ filterHdrSrc := cfg.NeutrinoMode.FilterHeadersSource
+ if blockHdrSrc != "" && filterHdrSrc != "" {
+ importCfg := &neutrino.HeadersImportConfig{
+ BlockHeadersSource: blockHdrSrc,
+ FilterHeadersSource: filterHdrSrc,
+ }
+
+ importCfg.ValidationFlags = neutrinoHeadersImportValidationFlags(
+ cfg.Bitcoin,
+ )
+
+ config.HeadersImport = importCfg
+ }
+
if cfg.NeutrinoMode.MaxPeers <= 0 {
return nil, nil, fmt.Errorf("a non-zero number must be set " +
"for neutrino max peers")
@@ -1872,6 +1896,21 @@ func initNeutrinoBackend(ctx context.Context, cfg *Config, chainDir string,
return neutrinoCS, cleanUp, nil
}
+// neutrinoHeadersImportValidationFlags returns the blockchain validation
+// flags to use when importing block headers via neutrino's chainimport
+// package. Local test networks fall back to BFFastAdd to keep harness
+// imports cheap; public networks keep contextual header validation enabled
+// so the imported chain is held to the same standard as P2P headers.
+func neutrinoHeadersImportValidationFlags(
+ chainCfg *lncfg.Chain) blockchain.BehaviorFlags {
+
+ if chainCfg.IsLocalNetwork() {
+ return blockchain.BFFastAdd
+ }
+
+ return blockchain.BFNone
+}
+
// parseHeaderStateAssertion parses the user-specified neutrino header state
// into a headerfs.FilterHeader.
func parseHeaderStateAssertion(state string) (*headerfs.FilterHeader, error) {
Why this scored 32/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.