What changed, and why it matters
This commit tightens validation of a Lightning network peer message called start_batch. Previously, the software only rejected batch sizes larger than 20. Now it also rejects batch sizes of 0 or 1, which the protocol specification says must be ignored with a warning. The change is a standards-compliance fix; it does not by itself look like a critical vulnerability, but it removes a case where a peer could request a meaningless batch and the node would accept it.
No urgent action required beyond normal patching. Node operators should update to include this commit to remain BOLT 2 compliant. Reviewers may want to confirm that other start_batch edge cases (e.g., non-commit_sig message types) are handled consistently with the specification.
Security signals we found
Protocol compliance fix for BOLT 2 start_batch validation
Adds lower-bound validation that was previously missing
Prevents acceptance of degenerate batch sizes (0, 1)
Sends a Warning message to the peer as required by spec
Evidence from the diff
In PeerConnection.scala, the condition guarding the start_batch handling was expanded from msg.batchSize > 20 to msg.batchSize <= 1 || msg.batchSize > 20. This aligns with BOLT 2’s requirement that a receiving node MUST ignore start_batch when batch_size is not strictly greater than 1 and SHOULD send a Warning. The node now logs a debug message and sends a Warning instead of entering a batching state for size 0 or 1. Tests were added for size 0 and size 1.
Changed components
eclair-core/src/main/scala/fr/acinq/eclair/io/PeerConnection.scalaLightning protocol peer connection handlingstart_batch / batching commit_sig message processingInspect captured patch +25 / −3
diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/io/PeerConnection.scala b/eclair-core/src/main/scala/fr/acinq/eclair/io/PeerConnection.scala
index 4a81d38..fff1d8a 100644
--- a/eclair-core/src/main/scala/fr/acinq/eclair/io/PeerConnection.scala
+++ b/eclair-core/src/main/scala/fr/acinq/eclair/io/PeerConnection.scala
@@ -363,9 +363,9 @@ class PeerConnection(keyPair: KeyPair, conf: PeerConnection.Conf, switchboard: A
log.debug("ignoring start_batch: we only support batching commit_sig messages")
d.transport ! Warning(msg.channelId, "invalid start_batch message: we only support batching commit_sig messages")
stay()
- } else if (msg.batchSize > 20) {
- log.debug("ignoring start_batch with batch_size = {} > 20", msg.batchSize)
- d.transport ! Warning(msg.channelId, "invalid start_batch message: batch_size must not be greater than 20")
+ } else if (msg.batchSize <= 1 || msg.batchSize > 20) {
+ log.debug("ignoring start_batch with invalid batch_size = {} (max = 20)", msg.batchSize)
+ d.transport ! Warning(msg.channelId, "invalid start_batch message: batch_size must be greater than 1 and not be greater than 20")
stay()
} else {
log.debug("starting commit_sig batch of size {} for channel_id={}", msg.batchSize, msg.channelId)
diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/io/PeerConnectionSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/io/PeerConnectionSpec.scala
index cc7904d..87d4da3 100644
--- a/eclair-core/src/test/scala/fr/acinq/eclair/io/PeerConnectionSpec.scala
+++ b/eclair-core/src/test/scala/fr/acinq/eclair/io/PeerConnectionSpec.scala
@@ -559,6 +559,28 @@ class PeerConnectionSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike wi
transport.expectMsg(TransportHandler.ReadAck(commitSig3))
peer.expectMsg(commitSig3)
peer.expectNoMessage(100 millis)
+
+ // We receive a batch with size=0: we ignore it.
+ val startBatch4 = StartBatch(channelId, batchSize = 0, TlvStream(StartBatchTlv.MessageType(132)))
+ val commitSig4 = CommitSig(channelId, IndividualSignature(randomBytes64()), Nil, TlvStream(CommitSigTlv.FundingTx(randomTxId())))
+ transport.send(peerConnection, startBatch4)
+ transport.expectMsg(TransportHandler.ReadAck(startBatch4))
+ transport.expectMsgType[Warning]
+ transport.send(peerConnection, commitSig4)
+ transport.expectMsg(TransportHandler.ReadAck(commitSig4))
+ peer.expectMsg(commitSig4)
+ peer.expectNoMessage(100 millis)
+
+ // We receive a batch with size=1: we ignore it.
+ val startBatch5 = StartBatch(channelId, batchSize = 1, TlvStream(StartBatchTlv.MessageType(132)))
+ val commitSig5 = CommitSig(channelId, IndividualSignature(randomBytes64()), Nil, TlvStream(CommitSigTlv.FundingTx(randomTxId())))
+ transport.send(peerConnection, startBatch5)
+ transport.expectMsg(TransportHandler.ReadAck(startBatch5))
+ transport.expectMsgType[Warning]
+ transport.send(peerConnection, commitSig5)
+ transport.expectMsg(TransportHandler.ReadAck(commitSig5))
+ peer.expectMsg(commitSig5)
+ peer.expectNoMessage(100 millis)
}
test("react to peer's bad behavior") { f =>
Why this scored 25/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.