
Rotating a Compromised LND Macaroon in BTCPay Server
BTCPay Server's August 7 advisory isn't solved by updating alone. We show you how to rotate your LND macaroon and kill any stolen credential, without moving funds or touching your channels.
Librería de Satoshi ·
A 5-minute incident response drill you can run on your own node.
The BTCPay Server advisory from August 7 is clear: update to 2.4.2 and you’re done. The update regenerates your macaroons automatically.
That’s true, but only for the doors BTCPay controls.
If you expose your LND node on your own (your own reverse proxy, a forwarded port, your own Tor tunnel), that stolen macaroon is still alive after the update. BTCPay can’t rotate a credential on a door it doesn’t know exists. And that is exactly the kind of setup advanced operators tend to have.
This tutorial is for two cases:
- (a) You expose LND on your own, in addition to through BTCPay.
- (b) You haven’t been able to update yet and want to rotate as a stopgap.
Already updated to 2.4.2 on a standard install and don’t expose LND on your own? Your macaroons have already been rotated automatically, so you don’t need to run this tutorial. Still go through the rest of the checklist below (review suspicious activity, move funds out of the hot wallet, etc.).
First, relax: macaroons are access credentials, not the keys to your funds. Rotating them does not move coins, does not close channels, and does not change your node’s identity. Your seed stays intact.
What you’re going to do
- Identify the current macaroon and check that it works.
- Delete the macaroons and the root key database.
- Restart LND from the host.
- Verify that the new credential works and the old one is rejected: same node, same funds.
Prerequisites
- A BTCPay Server running with the LND (bitcoin) container:
btcpayserver_lnd_bitcoin. - Shell access to the host.
The mental model (read this first)
A macaroon is a signed token. LND doesn’t store the token as the source of truth; it stores a root key in macaroons.db and bakes macaroons from it when they’re needed.
That single fact defines the whole procedure:
Deleting the .macaroon files does nothing. LND bakes byte-for-byte identical copies from the root key on the next startup. To truly rotate, you have to destroy the root key in macaroons.db to force LND to generate a new one.
Delete the tokens and the key. Not just the tokens.
Step 1: Capture the “before” state
Enter the node and check that the current credential is valid.
docker exec -it btcpayserver_lnd_bitcoin bash
# ---- now inside the container ----
cd /root/.lnd
alias li='lncli --macaroonpath /root/.lnd/admin.macaroon'
# Identify the current macaroon
sha256sum admin.macaroon
# Save a copy to prove later that it dies.
cp admin.macaroon OLD.bak
# Check that it works: the node responds.
li getinfo | grep identity_pubkey
Write down the identity_pubkey. It must be identical at the end. If it changes, you rotated the node, not the credential, and that is a different (and wrong) outcome.
Step 2: Rotate by deleting the macaroons and the root key
You’re still inside the container.
rm -f *.macaroon \
data/chain/bitcoin/regtest/*.macaroon \
data/chain/bitcoin/regtest/macaroons.db
ls OLD.bak # our saved copy survives
exit
Explanation: “Deleting only the .macaroon files does nothing, LND bakes identical copies again from the root key. The root key lives in macaroons.db, so it has to go too.”
Note on paths: the macaroon paths encode your network. This example is regtest. On a real node, switch to mainnet (data/chain/bitcoin/mainnet/...). Check your actual path with ls data/chain/bitcoin/.
Step 3: Restart LND from the host
On the host:
docker restart btcpayserver_lnd_bitcoin
Explanation: “LND keeps macaroons.db open, and it is PID 1 of its own container, so it can’t be restarted cleanly from inside. The restart comes from outside. When it starts without a root key, LND generates a new one and regenerates its macaroons.”
Give it a few seconds to unlock and come back up.
Step 4: Verify that the new one works, the old one is dead, and the node didn’t change
Enter again and compare side by side.
docker exec -it btcpayserver_lnd_bitcoin bash
cd /root/.lnd
alias li='lncli --macaroonpath /root/.lnd/admin.macaroon'
# NEW fingerprint: must be DIFFERENT from Step 1
sha256sum admin.macaroon
# The old one, to compare side by side
sha256sum OLD.bak
# The NEW credential works, and it's the SAME node
li getinfo | grep identity_pubkey
# The OLD credential is rejected: "signature mismatch" = DEAD
lncli --macaroonpath /root/.lnd/OLD.bak getinfo
# Cleanup
rm -f OLD.bak
exit
Explanation: “New fingerprint, so the root key really rotated. The new macaroon works. The stolen copy is now rejected with a signature mismatch. Same pubkey, so channels and funds never moved. BTCPay and RTL have already reconnected on their own.”
Success criteria:
| Check | Expected result |
|---|---|
sha256sum admin.macaroon |
Different from Step 1 |
New macaroon with getinfo |
Works |
identity_pubkey |
Same as Step 1 |
OLD.bak getinfo |
signature mismatch error |
If all four hold: the lock has changed, the stolen key is scrap, and the node never moved.
Reconnect your clients
BTCPay’s internal LND connection and the bundled RTL normally reconnect on their own. Anything that uses an exported macaroon has to be re-paired with the new one:
- Zeus / mobile wallets: scan the new connection QR code again.
- RTL (standalone), scripts, APIs: upload the new
admin.macaroon(or a bakery macaroon with narrowed permissions). - Any custom integration holding the old macaroon in hex/base64: update it.
The old credential is now invalid everywhere, so anything you don’t update will fail authentication until you re-pair it. That’s exactly the point.
Where this fits in the full response
Rotating the macaroon is one step. For the August 7 incident, the full list is:
- Update to 2.4.2: Admin Panel → Server → Maintenance → Update. Confirm the version in the footer and that LND ended up on 0.21.1. On a standard install, this already regenerates the macaroons automatically. (Can’t update right now? Shut the server down; a server that’s off can’t be exploited.)
- Rotate macaroons +
macaroons.dbmanually: this tutorial. Only needed if you expose LND on your own (proxy, Tor or your own port) or while you still can’t update. - Rotate authentication on every Lightning backend and update the integrations.
- Move the funds out of any on-chain hot wallet created by BTCPay, and then recreate it.
- Update NBXplorer to 2.6.10 if you use it.
In most cases, the update already changes the lock for you. The manual rotation steps are for the doors BTCPay can’t see or lock on its own.
Scam alert
After public advisories, “let me help you migrate your funds” scams show up. The rule never changes:
No legitimate party, not BTCPay, not anyone, will ever ask you for your seed, private key, password or macaroons.
Check every instruction against the official channels before acting.
Questions this tutorial answers up front:
- “Do I lose my Lightning channels if I regenerate the macaroons?” No. Macaroons are access credentials, not keys to funds. Channels and balances stay intact.
- “Does this affect my hardware wallet?” No. This is a server operator issue, separate from any hardware wallet incident.