P700 / / Crypto

BOLT11 invoice rules tightened after a Lightning withdrawal attack

Lightning invoices must now carry exactly one payment hash, after duplicate hashes let an attacker get withdrawals paid twice.

Visualisation of the Lightning Network: a dense red cluster of nodes and channels
Photo: StopAndDecrypt, CC BY-SA 4.0

A BOLT11 invoice, the standard Lightning payment request, must now contain exactly one payment hash and exactly one payment secret. Software has to reject anything else. The Lightning specification was changed on 19 October 2026 after an attacker used invoices with two payment hashes to make paid withdrawals look unpaid, and to get paid out twice.

If you only scan QR codes and pay, nothing changes for you. If you run a service that pays out over Lightning, such as a bot, an exchange, a shop with refunds or a faucet, read on.

What happened

A BOLT11 invoice is a string of tagged fields: amount, description, expiry, the payment hash ("p") and the payment secret ("s"). The payment hash is the receipt. Once the payment goes through, the payer learns the matching preimage, and that proves it paid.

Until now the specification did not forbid an invoice from carrying the payment hash twice. It only recommended that payers use the first "p" field. Not every library followed that advice: some read the first hash, others the last.

According to Lightning Labs CTO Olaoluwa Osuntokun (roasbeef), this gap was used against a popular Telegram peer-to-peer trading bot. Bitcoin Optech names it as LNP2PBot. The attacker sent withdrawal invoices with two different payment hashes. The bot's invoice parser recorded the withdrawal under one hash, while its Lightning node paid using the other. When the bot checked its records, the withdrawal looked unpaid, so it could be paid again. No public loss figure has been given.

What the BOLT11 invoice rule says now

The change is BOLTs pull request #1357, opened by roasbeef on 10 September and merged on 19 October. A reader of an invoice must fail the payment unless it contains:

  • exactly one payment hash field ("p"), and
  • exactly one payment secret field ("s").

A missing field fails. So does a second copy, even if both copies hold the same value. The test vectors in the specification include an invoice that repeats the same hash, so software must count the fields, not just compare their values. The PR also moved the invoice test vectors into a machine-readable JSON file, so developers can test their parsers against the new rules.

Which software is fixed

  • lnd rejects duplicate payment hashes since PR #11190, merged on 23 September. The fix shipped in v0.20.5-beta and v0.21.4-beta. A second lnd change that also rejects a duplicate payment secret was still open on 27 October.
  • ZEUS wallet says it now matches lnd's behaviour.
  • Core Lightning, LDK and Eclair: none of our sources says whether they already reject duplicate fields. If you run one of them, check its release notes or ask the developers.

What to do if you pay out over Lightning

  1. Update your node and your invoice library. On lnd, that means v0.20.5-beta or v0.21.4-beta or newer.
  2. Use one parser. The attack only worked because two pieces of software read the same invoice differently. Take the payment hash from the same code that sends the payment, or from the payment result your node returns, and not from your own decoding of the string.
  3. Reject odd invoices before paying. Missing or repeated "p" or "s" fields mean you stop.
  4. Reconcile against the node. Before you treat a withdrawal as failed and pay again, ask your node whether a payment to that hash succeeded. This case shows why.
  5. Remember that decoding is not paying. Some invoices that a decoder accepts are only rejected later in payment processing. A clean decode does not mean the payment will go through.

Why it matters

This is not a hole in Lightning's cryptography. It is a gap between what the spec allowed and how people wrote software around it. The same kind of trick hit custodial backends in 2023, when invoices were re-signed with a borrowed payment hash. The lesson is the same: the payment hash is a receipt, not an identity check, and your accounting has to follow what your node actually did.

We take Lightning at the Centralny Crypto Bar at ZOLAK, so this one is close to home. If you want the background on Lightning node security, our earlier post on the Core Lightning attack warning covers what node operators patched in October.

Not financial advice.

Sources

Crypto · Lightning