eclair-cli parseinvoice silently accepts a BOLT 11 invoice containing non-zero bech32 padding bits, which is explicitly invalid per BIP-173. It also silently rewrites the serialized field in its response to a corrected version of the invoice, hiding the fact that the input was malformed.
Spec References
-
BOLT 11:
"MUST parse the address as Bech32, as specified in BIP-0173"
-
BIP-173:
"Any incomplete group at the end MUST be 4 bits or less, MUST be all zeroes, and is discarded."
In BOLT 11, I see there is a requirement for the writer: "MUST pad field data to a multiple of 5 bits, using 0s."
However, I don’t see any requirement for the reader in above case during parsing, So, I think this should also be made explicit in the spec?
Inputs
- Invoice 1 (invalid - non-zero padding):
lnbc1qqqsqqqqqq4q8pq9pqqqqq8pqq9q8pdqqaqqqqqaqqqqqqq2jqfq5jppppsp5555555555555555555ppppppppppaaaakaaaaaallllllzqaaaqaaqqqqqaqqqqqqq2jqfq5jpppppp55y55555qqqqqwvq6nsqqqrqqqqqqqqqqqqq9qpqqqqqqxlllqqqqqqqqqqqqqqqcqqqqqqqqqqq9qvlllllllllwzrllqfllllllllllllllllqlll5jqlqvalllelllllqqqqqqqqllllll55555555lllllqqjjc7mu
{
"prefix": "lnbc",
"timestamp": 524288,
"nodeId": "02d1840657fa8d4c0fa9ce7ef698bebb4a227cc2893a0dd7b871a2fe7c5f3a85fe",
"serialized": "lnbc1qqqsqqqqqq4q8pq9pqqqqq8pqq9q8pdqqaqqqqqaqqqqqqq2jqfq5jppppsp5555555555555555555ppppppppppaaaakaaaaaallllllzqaaaqsaqqqqqaqqqqqqq2jqfq5jpppppp55y55555qqqqqwvq6nsqqqrqqqqqqqqqqqqq9qpqqqqqqxlllqqqqqqqqqqqqqqqcqqqqqqqqqqq9qvlllllllllwzrllqfllllllllllllllllqlll5jqlqvalllelllllqqqqqqqqllllll55555555lllllqq7hegzf",
"description": "",
"paymentHash": "a1294a5280000007301a9c00000c00000000000000005004000000037fff0000",
"features": {
"activated": {},
"unknown": []
},
"routingInfo": []
}
- Invoice 2 (valid - zero padding):
lnbc1qqqsqqqqqq4q8pq9pqqqqq8pqq9q8pdqqaqqqqqaqqqqqqq2jqfq5jppppsp5555555555555555555ppppppppppaaaakaaaaaallllllzqaaaqsaqqqqqaqqqqqqq2jqfq5jpppppp55y55555qqqqqwvq6nsqqqrqqqqqqqqqqqqq9qpqqqqqqxlllqqqqqqqqqqqqqqqcqqqqqqqqqqq9qvlllllllllwzrllqfllllllllllllllllqlll5jqlqvalllelllllqqqqqqqqllllll55555555lllllqq7hegzf
{
"prefix": "lnbc",
"timestamp": 524288,
"nodeId": "036fc69aed4740b8d060a99047e080c699ad803381bcfa2f19be91fcc8c0b4fb1c",
"serialized": "lnbc1qqqsqqqqqq4q8pq9pqqqqq8pqq9q8pdqqaqqqqqaqqqqqqq2jqfq5jppppsp5555555555555555555ppppppppppaaaakaaaaaallllllzqaaaqsaqqqqqaqqqqqqq2jqfq5jpppppp55y55555qqqqqwvq6nsqqqrqqqqqqqqqqqqq9qpqqqqqqxlllqqqqqqqqqqqqqqqcqqqqqqqqqqq9qvlllllllllwzrllqfllllllllllllllllqlll5jqlqvalllelllllqqqqqqqqllllll55555555lllllqq7hegzf",
"description": "",
"paymentHash": "a1294a5280000007301a9c00000c00000000000000005004000000037fff0000",
"features": {
"activated": {},
"unknown": []
},
"routingInfo": []
}
FYI
CLN
$ lightning-cli decode lnbc1qqqsqqqqqq4q8pq9pqqqqq8pqq9q8pdqqaqqqqqaqqqqqqq2jqfq5jppppsp5555555555555555555ppppppppppaaaakaaaaaallllllzqaaaqaaqqqqqaqqqqqqq2jqfq5jpppppp55y55555qqqqqwvq6nsqqqrqqqqqqqqqqqqq9qpqqqqqqxlllqqqqqqqqqqqqqqqcqqqqqqqqqqq9qvlllllllllwzrllqfllllllllllllllllqlll5jqlqvalllelllllqqqqqqqqllllll55555555lllllqqjjc7mu
{
"code": -32602,
"message": "string: non-zero trailing bits: invalid token '\"lnbc1qqqsqqqqqq4q8pq9pqqqqq8pqq9q8pdqqaqqqqqaqqqqqqq2jqfq5jppppsp5555555555555555555ppppppppppaaaakaaaaaallllllzqaaaqaaqqqqqaqqqqqqq2jqfq5jpppppp55y55555qqqqqwvq6nsqqqrqqqqqqqqqqqqq9qpqqqqqqxlllqqqqqqqqqqqqqqqcqqqqqqqqqqq9qvlllllllllwzrllqfllllllllllllllllqlll5jqlqvalllelllllqqqqqqqqllllll55555555lllllqqjjc7mu\"'"
}
$ lightning-cli decode lnbc1qqqsqqqqqq4q8pq9pqqqqq8pqq9q8pdqqaqqqqqaqqqqqqq2jqfq5jppppsp5555555555555555555ppppppppppaaaakaaaaaallllllzqaaaqsaqqqqqaqqqqqqq2jqfq5jpppppp55y55555qqqqqwvq6nsqqqrqqqqqqqqqqqqq9qpqqqqqqxlllqqqqqqqqqqqqqqqcqqqqqqqqqqq9qvlllllllllwzrllqfllllllllllllllllqlll5jqlqvalllelllllqqqqqqqqllllll55555555lllllqq7hegzf
{
"type": "bolt11 invoice",
"currency": "bc",
"created_at": 524288,
"expiry": 3600,
"payee": "036fc69aed4740b8d060a99047e080c699ad803381bcfa2f19be91fcc8c0b4fb1c",
"description": "",
"min_final_cltv_expiry": 18,
"payment_secret": "a5294a5294a5294a5294a50210842108421ef7bdb77bdef7bfffffff881def41",
"features": "",
"extra": [
{
"tag": "q",
"data": ""
},
{
"tag": "4",
"data": "pq9pqqq"
},
{
"tag": "q",
"data": "pqq9q8p"
},
{
"tag": "a",
"data": ""
},
{
"tag": "q",
"data": ""
},
{
"tag": "a",
"data": ""
},
{
"tag": "q",
"data": ""
},
{
"tag": "q",
"data": "jqfq5jpppp"
},
{
"tag": "a",
"data": ""
},
{
"tag": "q",
"data": ""
},
{
"tag": "a",
"data": ""
},
{
"tag": "q",
"data": ""
},
{
"tag": "q",
"data": "jqfq5jpppp"
},
{
"tag": "q",
"data": ""
}
],
"payment_hash": "a1294a5280000007301a9c00000c00000000000000005004000000037fff0000",
"signature": "3041021c00c000000000000002819fffffffffff7087ff813fffffffffffffff022100ffffe0ffff4903e0677fffe7fffffe0000000001fffffffd294a5294a7fffffc",
"valid": true
}
LND
$ lncli decodepayreq lnbc1qqqsqqqqqq4q8pq9pqqqqq8pqq9q8pdqqaqqqqqaqqqqqqq2jqfq5jppppsp5555555555555555555ppppppppppaaaakaaaaaallllllzqaaaqaaqqqqqaqqqqqqq2jqfq5jpppppp55y55555qqqqqwvq6nsqqqrqqqqqqqqqqqqq9qpqqqqqqxlllqqqqqqqqqqqqqqqcqqqqqqqqqqq9qvlllllllllwzrllqfllllllllllllllllqlll5jqlqvalllelllllqqqqqqqqllllll55555555lllllqqjjc7mu
{
"error": "invalid incomplete group"
}
$ lncli decodepayreq lnbc1qqqsqqqqqq4q8pq9pqqqqq8pqq9q8pdqqaqqqqqaqqqqqqq2jqfq5jppppsp5555555555555555555ppppppppppaaaakaaaaaallllllzqaaaqsaqqqqqaqqqqqqq2jqfq5jpppppp55y55555qqqqqwvq6nsqqqrqqqqqqqqqqqqq9qpqqqqqqxlllqqqqqqqqqqqqqqqcqqqqqqqqqqq9qvlllllllllwzrllqfllllllllllllllllqlll5jqlqvalllelllllqqqqqqqqllllll55555555lllllqq7hegzf
{
"destination": "036fc69aed4740b8d060a99047e080c699ad803381bcfa2f19be91fcc8c0b4fb1c",
"payment_hash": "a1294a5280000007301a9c00000c00000000000000005004000000037fff0000",
"num_satoshis": "0",
"timestamp": "524288",
"expiry": "3600",
"description": "",
"description_hash": "",
"fallback_addr": "",
"cltv_expiry": "18",
"route_hints": [],
"payment_addr": "a5294a5294a5294a5294a50210842108421ef7bdb77bdef7bfffffff881def41",
"num_msat": "0",
"features": {},
"blinded_paths": []
}
PS: This was found during fuzzing while I was adding BOLT 11 invoice deserialization fuzz tests, and it serves as a reminder of the importance of having a good fuzz test suite for Eclair.
eclair-cli parseinvoicesilently accepts a BOLT 11 invoice containing non-zero bech32 padding bits, which is explicitly invalid per BIP-173. It also silently rewrites the serialized field in its response to a corrected version of the invoice, hiding the fact that the input was malformed.Spec References
BOLT 11:
"MUST parse the address as Bech32, as specified in BIP-0173"
BIP-173:
"Any incomplete group at the end MUST be 4 bits or less, MUST be all zeroes, and is discarded."
In BOLT 11, I see there is a requirement for the writer: "MUST pad field data to a multiple of 5 bits, using 0s."
However, I don’t see any requirement for the reader in above case during parsing, So, I think this should also be made explicit in the spec?
Inputs
lnbc1qqqsqqqqqq4q8pq9pqqqqq8pqq9q8pdqqaqqqqqaqqqqqqq2jqfq5jppppsp5555555555555555555ppppppppppaaaakaaaaaallllllzqaaaqaaqqqqqaqqqqqqq2jqfq5jpppppp55y55555qqqqqwvq6nsqqqrqqqqqqqqqqqqq9qpqqqqqqxlllqqqqqqqqqqqqqqqcqqqqqqqqqqq9qvlllllllllwzrllqfllllllllllllllllqlll5jqlqvalllelllllqqqqqqqqllllll55555555lllllqqjjc7mu{ "prefix": "lnbc", "timestamp": 524288, "nodeId": "02d1840657fa8d4c0fa9ce7ef698bebb4a227cc2893a0dd7b871a2fe7c5f3a85fe", "serialized": "lnbc1qqqsqqqqqq4q8pq9pqqqqq8pqq9q8pdqqaqqqqqaqqqqqqq2jqfq5jppppsp5555555555555555555ppppppppppaaaakaaaaaallllllzqaaaqsaqqqqqaqqqqqqq2jqfq5jpppppp55y55555qqqqqwvq6nsqqqrqqqqqqqqqqqqq9qpqqqqqqxlllqqqqqqqqqqqqqqqcqqqqqqqqqqq9qvlllllllllwzrllqfllllllllllllllllqlll5jqlqvalllelllllqqqqqqqqllllll55555555lllllqq7hegzf", "description": "", "paymentHash": "a1294a5280000007301a9c00000c00000000000000005004000000037fff0000", "features": { "activated": {}, "unknown": [] }, "routingInfo": [] }lnbc1qqqsqqqqqq4q8pq9pqqqqq8pqq9q8pdqqaqqqqqaqqqqqqq2jqfq5jppppsp5555555555555555555ppppppppppaaaakaaaaaallllllzqaaaqsaqqqqqaqqqqqqq2jqfq5jpppppp55y55555qqqqqwvq6nsqqqrqqqqqqqqqqqqq9qpqqqqqqxlllqqqqqqqqqqqqqqqcqqqqqqqqqqq9qvlllllllllwzrllqfllllllllllllllllqlll5jqlqvalllelllllqqqqqqqqllllll55555555lllllqq7hegzf{ "prefix": "lnbc", "timestamp": 524288, "nodeId": "036fc69aed4740b8d060a99047e080c699ad803381bcfa2f19be91fcc8c0b4fb1c", "serialized": "lnbc1qqqsqqqqqq4q8pq9pqqqqq8pqq9q8pdqqaqqqqqaqqqqqqq2jqfq5jppppsp5555555555555555555ppppppppppaaaakaaaaaallllllzqaaaqsaqqqqqaqqqqqqq2jqfq5jpppppp55y55555qqqqqwvq6nsqqqrqqqqqqqqqqqqq9qpqqqqqqxlllqqqqqqqqqqqqqqqcqqqqqqqqqqq9qvlllllllllwzrllqfllllllllllllllllqlll5jqlqvalllelllllqqqqqqqqllllll55555555lllllqq7hegzf", "description": "", "paymentHash": "a1294a5280000007301a9c00000c00000000000000005004000000037fff0000", "features": { "activated": {}, "unknown": [] }, "routingInfo": [] }FYI
CLN
$ lightning-cli decode lnbc1qqqsqqqqqq4q8pq9pqqqqq8pqq9q8pdqqaqqqqqaqqqqqqq2jqfq5jppppsp5555555555555555555ppppppppppaaaakaaaaaallllllzqaaaqaaqqqqqaqqqqqqq2jqfq5jpppppp55y55555qqqqqwvq6nsqqqrqqqqqqqqqqqqq9qpqqqqqqxlllqqqqqqqqqqqqqqqcqqqqqqqqqqq9qvlllllllllwzrllqfllllllllllllllllqlll5jqlqvalllelllllqqqqqqqqllllll55555555lllllqqjjc7mu { "code": -32602, "message": "string: non-zero trailing bits: invalid token '\"lnbc1qqqsqqqqqq4q8pq9pqqqqq8pqq9q8pdqqaqqqqqaqqqqqqq2jqfq5jppppsp5555555555555555555ppppppppppaaaakaaaaaallllllzqaaaqaaqqqqqaqqqqqqq2jqfq5jpppppp55y55555qqqqqwvq6nsqqqrqqqqqqqqqqqqq9qpqqqqqqxlllqqqqqqqqqqqqqqqcqqqqqqqqqqq9qvlllllllllwzrllqfllllllllllllllllqlll5jqlqvalllelllllqqqqqqqqllllll55555555lllllqqjjc7mu\"'" }$ lightning-cli decode lnbc1qqqsqqqqqq4q8pq9pqqqqq8pqq9q8pdqqaqqqqqaqqqqqqq2jqfq5jppppsp5555555555555555555ppppppppppaaaakaaaaaallllllzqaaaqsaqqqqqaqqqqqqq2jqfq5jpppppp55y55555qqqqqwvq6nsqqqrqqqqqqqqqqqqq9qpqqqqqqxlllqqqqqqqqqqqqqqqcqqqqqqqqqqq9qvlllllllllwzrllqfllllllllllllllllqlll5jqlqvalllelllllqqqqqqqqllllll55555555lllllqq7hegzf { "type": "bolt11 invoice", "currency": "bc", "created_at": 524288, "expiry": 3600, "payee": "036fc69aed4740b8d060a99047e080c699ad803381bcfa2f19be91fcc8c0b4fb1c", "description": "", "min_final_cltv_expiry": 18, "payment_secret": "a5294a5294a5294a5294a50210842108421ef7bdb77bdef7bfffffff881def41", "features": "", "extra": [ { "tag": "q", "data": "" }, { "tag": "4", "data": "pq9pqqq" }, { "tag": "q", "data": "pqq9q8p" }, { "tag": "a", "data": "" }, { "tag": "q", "data": "" }, { "tag": "a", "data": "" }, { "tag": "q", "data": "" }, { "tag": "q", "data": "jqfq5jpppp" }, { "tag": "a", "data": "" }, { "tag": "q", "data": "" }, { "tag": "a", "data": "" }, { "tag": "q", "data": "" }, { "tag": "q", "data": "jqfq5jpppp" }, { "tag": "q", "data": "" } ], "payment_hash": "a1294a5280000007301a9c00000c00000000000000005004000000037fff0000", "signature": "3041021c00c000000000000002819fffffffffff7087ff813fffffffffffffff022100ffffe0ffff4903e0677fffe7fffffe0000000001fffffffd294a5294a7fffffc", "valid": true }LND
$ lncli decodepayreq lnbc1qqqsqqqqqq4q8pq9pqqqqq8pqq9q8pdqqaqqqqqaqqqqqqq2jqfq5jppppsp5555555555555555555ppppppppppaaaakaaaaaallllllzqaaaqaaqqqqqaqqqqqqq2jqfq5jpppppp55y55555qqqqqwvq6nsqqqrqqqqqqqqqqqqq9qpqqqqqqxlllqqqqqqqqqqqqqqqcqqqqqqqqqqq9qvlllllllllwzrllqfllllllllllllllllqlll5jqlqvalllelllllqqqqqqqqllllll55555555lllllqqjjc7mu { "error": "invalid incomplete group" }$ lncli decodepayreq lnbc1qqqsqqqqqq4q8pq9pqqqqq8pqq9q8pdqqaqqqqqaqqqqqqq2jqfq5jppppsp5555555555555555555ppppppppppaaaakaaaaaallllllzqaaaqsaqqqqqaqqqqqqq2jqfq5jpppppp55y55555qqqqqwvq6nsqqqrqqqqqqqqqqqqq9qpqqqqqqxlllqqqqqqqqqqqqqqqcqqqqqqqqqqq9qvlllllllllwzrllqfllllllllllllllllqlll5jqlqvalllelllllqqqqqqqqllllll55555555lllllqq7hegzf { "destination": "036fc69aed4740b8d060a99047e080c699ad803381bcfa2f19be91fcc8c0b4fb1c", "payment_hash": "a1294a5280000007301a9c00000c00000000000000005004000000037fff0000", "num_satoshis": "0", "timestamp": "524288", "expiry": "3600", "description": "", "description_hash": "", "fallback_addr": "", "cltv_expiry": "18", "route_hints": [], "payment_addr": "a5294a5294a5294a5294a50210842108421ef7bdb77bdef7bfffffff881def41", "num_msat": "0", "features": {}, "blinded_paths": [] }PS: This was found during fuzzing while I was adding BOLT 11 invoice deserialization fuzz tests, and it serves as a reminder of the importance of having a good fuzz test suite for Eclair.