Use correct nonce in InvoiceRequest context
What changed, and why it matters
This commit fixes a bug in how Lightning invoice requests are created. Previously, the code generated a fresh random nonce for the invoice request context instead of reusing the nonce from the original offer. Because the two nonces no longer matched, later verification of the invoice request would fail. The fix simply uses the offer's nonce directly. This is a correctness bug in the BOLT 12 offers protocol flow rather than a traditional security vulnerability like theft or denial of service, but it could cause payment flows to break or messages to be rejected.
Treat as a bug fix that should be included in any release branch supporting BOLT 12 offers. Users relying on BOLT 12 invoice requests should upgrade to avoid payment flow failures. No immediate exploit mitigation is required beyond normal patching.
Security signals we found
Protocol correctness fix in BOLT 12 Offers flow
Nonce mismatch between offer and invoice request
Verification failure on received invoice request
No explicit security framing by vendor
Evidence from the diff
In lightning/src/offers/flow.rs, when building a MessageContext::Offers(OffersContext::InvoiceRequest), the code was calling Nonce::from_entropy_source(&*entropy) to create a new nonce. The correct behavior is to use the nonce from the offer (offer_nonce). The mismatch between the offer nonce and the invoice request context nonce would cause signature/verification checks to fail when the invoice request is later received and validated, because the receiver expects the invoice request to refer back to the offer’s nonce.
Changed components
lightning/src/offers/flow.rsBOLT 12 Offers / InvoiceRequest handlingMessageContext::Offers with OffersContext::InvoiceRequestInspect captured patch +1 / −2
diff --git a/lightning/src/offers/flow.rs b/lightning/src/offers/flow.rs
index 38f472b..7344828 100644
--- a/lightning/src/offers/flow.rs
+++ b/lightning/src/offers/flow.rs
@@ -1557,8 +1557,7 @@ where
.and_then(|builder| builder.build_and_sign(secp_ctx))
.map_err(|_| ())?;
- let nonce = Nonce::from_entropy_source(&*entropy);
- let context = MessageContext::Offers(OffersContext::InvoiceRequest { nonce });
+ let context = MessageContext::Offers(OffersContext::InvoiceRequest { nonce: offer_nonce });
let forward_invoice_request_path = self
.create_blinded_paths(peers, context)
.and_then(|paths| paths.into_iter().next().ok_or(()))?;
Why this scored 41/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.