Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to apply spending restrictions to a rune #7020

Closed
Amperstrand opened this issue Jan 28, 2024 · 5 comments
Closed

Unable to apply spending restrictions to a rune #7020

Amperstrand opened this issue Jan 28, 2024 · 5 comments
Assignees
Milestone

Comments

@Amperstrand
Copy link

Amperstrand commented Jan 28, 2024

Problem: how can you issue a rune which restricts the amount of sats that it can spend per request

There have been some loss of funds incidents that have been caused by programs like lnbits and btcpayserver being given unrestricted access to the lightning node. The impact of such incidents could be limited if they were accessing the lightning node through runes that were ratelimited in how much and how fast they could make payments.

PEER_ID=$(lightning-cli getinfo|jq -r .id)
rune=$(lightning-cli commando-rune restrictions='[["method=pay"],["pnameamountmsat<1001"]]' | jq -r .rune)
lightning-cli commando $PEER_ID pay "{\"bolt11\":\"$bolt11_invoice\", \"amount_msat\": 1000 }" $rune

The above creates a rune that can be used to pay bolt11 invoices that do not include an amount. The maximum that can be paid with this rune is 1 satoshi.

The problem is that it will only work for bolt11 invoices that do not specify the amount. If the bolt11 invoice asks for 1 satoshi, the pay command will fail because you cannot specify amount if it is encoded in the invoice:

{
   "code": -32602,
   "message": "msatoshi parameter unnecessary"
}

Possible solution 1: allow the pay command to specify the amount even when it is not necessary

If we allow the command to be used with a specified amount even when it is encoded in the invoice, I am pretty sure the rune restriction would be applied. Instead of requiring amount_msat to be None, it could be required to be either None or equal to what is encoded in the invoice. This would be the simplest way to solve this problem.

Possible solution 2: allow rune restrictions to apply to bolt11 invoice fields

Runes can look at integer fields and strings to apply restrictions. In this case, we want to make a restriction such that the amount encoded in the bolt11 invoice is less than X.

If runes allowed us to inspect the various fields of the bolt11 invoice, it would be possible to apply a restriction in this way.

Possible solution 3: use getroute and sendpay instead of pay

A possible way to restrict payment sizes would be to not issue a rune for pay but require the use of sendpay instead. With sendpay, I think amount_msat is a required field and so restricting the amount with a rune would work.

Amperstrand referenced this issue in Amperstrand/lightning Jan 28, 2024
Implements possible solution 1 
as described in this [https://github.com/ElementsProject/lightning/issues/7020](this issue).

This should allow you to use the pay command with a rune that restricts the amount that can be spent, even when the invoice contains the amount.
@tonyaldon
Copy link
Contributor

I'm not sure if this is what you want to accomplish, but you could write a plugin that intercepts payments done with the pay command and takes a decision to complete the payments based on the amount of the invoice.

See https://lnroom.live/2023-06-08-live-0006-core-lightning-rpc-command-hook-pay-command-and-bolt11-invoice/ for an example.

Amperstrand pushed a commit to Amperstrand/lightning that referenced this issue Jan 31, 2024
…invoice is equal to the amount of sats specified by the parameter.

Tested and seems to work.
ElementsProject#7020
@Amperstrand
Copy link
Author

I'm not sure if this is what you want to accomplish, but you could write a plugin that intercepts payments done with the pay command and takes a decision to complete the payments based on the amount of the invoice.

Yes, this is what I want to do.

LNBits, BTCPayserver and Boltcard can all be configured to access a lightning node. If there is a bug or security incident in them, one way to restrict loss of funds is through the use of credentials that have limited access (like runes).

I like the idea of intercepting and inspecting invoices as a plugin is a good idea, but it has one disadvantage: by doing it this way, the application would be given a rune to use the pay command. If the plugin is not loaded or fails, no interception happens and it has full access. So this could set you up for a future vulnerability where you think you have a firewall in place, but after updating the node the plugin is not correctly enabled and so the restriction is lifted.

There are other ways of solving this issue then in 7cbe45b. In fact, it seems kind of redundant: if you just want to pay an invoice, you need to decode the invoice and supply the amount. It might be better if you could just specify a max amount, and then any invoice under this will be accepted.

There is already maxfeepercent and maxfee. Maybe there should be a maxamount_msat.

I want a rune that can pay any invoice up to an amount. If you issue such a rune and rate limit it to 1 time per week with an expiry of 6 days it is in effect a single use voucher much like LNURLw.

But what I really want to use it for is giving LNBits and BTCPayserver the ability to pay invoices up to a limited amount in terms of both sats and rate limit. I nearly have LNBits working using the new CLNRest api as a funding source.

Amperstrand pushed a commit to Amperstrand/lnbits that referenced this issue Feb 5, 2024
… generate a new bolt11 invoice without amount_msat, and then use lightning-cli pay bolt11=bolt11_without_amount_msat amount_msat=amount_msat_parsed_from_bolt11_invoice ?

if so, it would allow the rune restriction to be applied to the amount_msat parameter
unfortunately the new bolt11 invoice without amount_msat is not signed by the issuing node, so the manipulated bolt11 invoice will not work
ElementsProject/lightning#7020
@Amperstrand
Copy link
Author

Pretty sure its not possible to take a bolt11 invoice, decode it, remove the amount, encode it as a bolt11 invoice again and then pay that. The reason for this is that I think the bolt11 invoice is signed by the issuing node(?).

So if we have a bolt11 invoice with the amount encoded in it, it is non-trivial to somehow use the pay plugin to pay it but apply a rune restriction.

@rustyrussell rustyrussell added this to the v24.05 milestone Mar 3, 2024
@rustyrussell rustyrussell self-assigned this Mar 3, 2024
@rustyrussell
Copy link
Contributor

Decoding a bolt11/bolt12 inside the rune code is non-trivial, however @ShahanaFarooqui convinced me that it's worth trying: we plan on attempting to implement it to judge this week.

@Amperstrand
Copy link
Author

Amperstrand commented May 13, 2024

#7165 fixes this issue.

rune=$(lightning-cli commando-rune restrictions='[["method=pay"], ["pinvbolt11_amount<2001"]]' | jq -r .rune)

The above should only be able to pay bolt11 invoices up to and including 2 sats.

With some clever rate limiting, it can be be a great way to give an application limited ability to spend from a core lightning instance.

Now that I know this is likely to show up in a future version of core lightning I will go back to working on making lnbits use runes when communicating over CLNRest.

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants