BTCPay Server Hot Wallet Sweeps: How Attackers Drained On-Chain Wallets and How to Protect Yours

The CyberSec Guru

Updated on:

BTCPay Server Hot Wallet Sweep

If you like this post, then please share it:

Buy me A Coffee!

Support The CyberSec Guru’s Mission

🔐 Fuel the cybersecurity crusade by buying me a coffee! Why your support matters: Zero paywalls: Keep the main content 100% free for learners worldwide.

“Your coffee keeps the servers running and the knowledge flowing in our fight against cybercrime.”☕ Support My Work

Buy Me a Coffee Button

On November 1, 2026, the maintainers of BTCPay Server, the open-source Bitcoin payment processor, told every self-hosted operator to run ./btcpay-down.sh and shut down their container stacks. Reports had come in that on-chain hot wallets on live instances were being swept by unauthorized actors. Within hours, founder Nicolas Dorier and the incident response team narrowed the active exploitation window to servers running BTCPay Server 2.4.1 (tagged July 23, 2026) or earlier. Servers on version 2.4.7, released October 29, 2026, showed no credible reports of compromise. The maintainers did not call the newer build immune, though, because root-cause analysis was still under way.

Taken alone, an exploit against three-month-old software looks like ordinary missed patching. BTCPay’s recent history makes it look like the second half of a longer crisis. On August 6, 2026, less than ninety days earlier, the project pushed version 2.4.2 to fix an actively exploited authentication bypass that let unauthenticated remote attackers steal LND .macaroon bearer credentials and drain merchant Lightning channels. Between that advisory and 2.4.7, the team shipped six releases (2.4.2 through 2.4.7) that hardened authentication state, removed legacy API surfaces, tightened multi-tenant store permissions, and fixed 85 vulnerability findings reported by Anthropic’s open source software (OSS) security scanner.

This post follows how attackers got from stealing Lightning bearer tokens in August to sweeping on-chain hot wallets in November. That means looking at how .NET web apps, UTXO indexers, PostgreSQL databases, and container volume mounts store and unlock signing keys when an operator picks convenience over hardware isolation.

BTCPay Server on X
BTCPay Server on X

How a BTCPay Server deployment stores private keys

Container topology and inter-container communication

Merchants often talk about BTCPay Server as one program, but a production deployment built with btcpayserver-docker is a cluster of at least seven containers on a shared Docker bridge network. Their inter-process communication (IPC) paths and shared volume mounts make up the internal attack surface.

At the edge, nginx with docker-gen and acme-companion (or a Traefik equivalent) terminates TLS and routes HTTP traffic to the btcpayserver container, which runs on .NET 10 (migrated from .NET 8 earlier in the 2026 release cycle). Behind it sits NBXplorer, a lightweight blockchain indexer and Hierarchical Deterministic (HD) wallet tracker written by Nicolas Dorier. NBXplorer talks to a local bitcoind (Bitcoin Core) container over JSON-RPC and the peer-to-peer (P2P) protocol. A shared postgres container stores state for both BTCPay Server and NBXplorer, and optional sidecars (electrs, LND, Core Lightning, or Eclair) handle address indexing and Lightning settlement.

Watch-only wallets versus hot wallets

By default, BTCPay keeps a hard cryptographic line between generating invoices and signing transactions. A merchant using a hardware wallet or offline cold storage gives the server only an account-level extended public key (xpub, ypub, or zpub, depending on whether the derivation follows BIP-44 legacy, BIP-49 nested SegWit, or BIP-84 native SegWit; BIP-86 Taproot uses an output descriptor). BTCPay passes that derivation strategy to NBXplorer, which derives a fresh child public key for each invoice (m/0/i for receiving addresses, m/1/i for change) without ever holding the extended private key (xprv).

NBXplorer watches the bitcoind mempool and validated blocks for transactions that pay those derived scriptPubKeys, then notifies BTCPay through its internal HTTP API and WebSocket event bus. An attacker with full remote code execution or database access on a watch-only instance can read transaction history or swap in a different xpub to redirect future payments. They cannot produce a valid witness or scriptSig to spend existing Unspent Transaction Outputs (UTXOs).

That isolation ends when an operator creates or imports a hot wallet. To support automated payouts, pull payments, instant refunds, and treasury scripting through the Greenfield API, BTCPay lets a store generate or upload a BIP-39 mnemonic seed on the server itself. At that point the server stops being an unprivileged invoice coordinator and becomes an internet-facing custodian.

Hot wallet keys are handled by BTCPay’s internal wallet services (HotwalletSafe and the DerivationSchemeSettings controllers) working closely with NBXplorer’s key storage. When a hot wallet is created in the web UI or through the Greenfield endpoint POST /api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/generate, the request is proxied to NBXplorer’s GenerateWallet RPC. With the savePrivateKeys parameter set to true, which a working hot wallet requires, the master extkey (xprv) and optional BIP-39 mnemonic metadata are serialized and stored in NBXplorer’s PostgreSQL schema (or its local key-value repository in legacy setups), tied to that specific DerivationStrategy.

Application-layer authorization, not hardware, controls access to that key material. Between the btcpayserver and nbxplorer containers, requests are authenticated by a local bearer cookie file (.cookie) on a shared Docker volume, or not authenticated at all over the isolated bridge network, depending on the deployment template. NBXplorer trusts any request from the btcpayserver container that carries valid internal credentials.

📬 Stay Ahead of Cyber Threats

Get the latest cybersecurity news, critical vulnerabilities, threat intelligence, tutorials, and exclusive giveaways delivered straight to your inbox. No spam. Unsubscribe anytime.

Subscribe to the Newsletter →

So the only thing standing between an outsider and the decrypted xprv, a Partially Signed Bitcoin Transaction (PSBT), local in-memory signing of every input, and a broadcast through bitcoind is BTCPay’s ASP.NET Core authentication and policy pipeline. That pipeline checks the global PoliciesSettings.AllowHotWalletForAll flag (or administrator status) together with the store-level policy CanModifyStoreSettings (btcpay.store.canmodifystoresettings) or CanUseHotWallet. An adversary who hijacks an administrator session or bypasses the authorization middleware gets HotwalletSafe to run the full signing process on their behalf, and neither the database nor the indexer sees anything unusual.

Where LND macaroons fit in

Lightning has a similar concentration of credentials, especially on instances paired with LND. Core Lightning mostly relies on Unix domain sockets or mutual TLS (mTLS) with runes. LND authenticates gRPC and REST calls with macaroons, bearer tokens modeled on cookies that carry caveats and permissions verified through chained HMAC signatures.

In a standard BTCPay Docker stack, the lnd container writes unrestricted admin.macaroon, invoice.macaroon, and readonly.macaroon files to a shared Docker volume (/data/.lnd/…). That volume is bind-mounted into the btcpayserver container so the web app can manage channels and create BOLT-11 and BOLT-12 invoices. Anyone who pulls admin.macaroon along with the node’s tls.cert gets full programmatic control of the channel state and LND’s internal on-chain wallet, and BTCPay’s user database never comes into it.

August LND macaroon theft vs. November on-chain hot wallet sweeps

Coverage after the November 1 shutdown order often lumped the on-chain drains together with the August 2026 incident, as if one vulnerability explained both. Looking at the protocol paths, affected subsystems, and fixes, they are two separate phases. They hit overlapping versions (2.4.1 and earlier) but targeted different custody layers.

the August 2026 Greenfield API bypass and LND node drains

On August 6, 2026, BTCPay Server published an urgent advisory telling operators to upgrade to version 2.4.2 together with LND 0.21.1 and NBXplorer 2.6.10. Craig Raw (developer of Sparrow Wallet) and researchers @brunoerg and @benthecarman from the Bitcoin Red Team effort disclosed the flaw responsibly. It affected every version before 2.4.2, release candidates included.

Forensics on compromised public instances, including a high-profile node run by hardware wallet maker Foundation Devices, traced the intrusion to an authentication logic flaw in the Greenfield HTTP API. The standard web login enforced multi-factor authentication for accounts with Time-based One-Time Passwords (TOTP). The Greenfield API controller, however, accepted legacy HTTP Authorization: Basic headers carrying a base64-encoded email:password string, and a faulty state check let accounts with TOTP enabled skip the second factor entirely when they authenticated that way. This applied to accounts that had not registered a FIDO2/WebAuthn hardware key or Passkey.

Attackers who obtained valid credentials (through credential stuffing, phishing, or secondary unauthenticated readout primitives fixed in 2.4.2) and bypassed TOTP over Greenfield, or who used an unauthenticated endpoint exposure in pre-2.4.2 builds, went after the server’s Lightning configuration endpoints. They extracted the admin.macaroon file for the internal LND daemon and gained direct gRPC and REST control of the node. They then moved liquid outbound capacity through attacker-controlled routing nodes using spontaneous keysend payments or synthetic BOLT-11 invoices, and emptied LND’s internal on-chain wallet (lncli sendcoins, the SendCoins RPC).

During the August post-mortem, the BTCPay team clarified the scope. Their first emergency broadcast had told merchants to move all on-chain funds out as a precaution, but later code auditing confirmed that BTCPay’s native on-chain wallets, NBXplorer-backed hot wallets included, were not affected by the macaroon flaw. It exposed the LND credential path, not the HotwalletSafe and NBXplorer seed storage of non-LND stores.

Version 2.4.2 fixed the credential exposure, temporarily disabled public Docker network forwarding for the LND API (which broke external mobile wallet connections such as Zeus over Tor or clearnet until the setup was redesigned), regenerated admin.macaroon automatically on upgrade, and disabled Greenfield HTTP Basic authentication by default five minutes after the first user is created.

the November 1, 2026 admin intrusion and on-chain sweeps

The alert of November 1, 2026 reversed the August asset profile. Attackers were now sweeping native on-chain Bitcoin hot wallets managed directly by the BTCPay core application, instead of siphoning Lightning liquidity or LND’s internal wallet.

Nicolas Dorier’s first forensic disclosures said server logs from affected deployments showed the attackers authenticating as server administrators at the application layer. Every verified victim was also running BTCPay Server 2.4.1 (July 23, 2026) or older.

That overlap between the version ceiling (2.4.1 or earlier) and full ServerAdmin takeover leaves three explanations under investigation by the incident response team. I would treat all three as hypotheses until the project publishes its logs.

  1. Dormant credentials used late. Attackers who broke into pre-2.4.2 servers during the July to August window may not have stopped at admin.macaroon files. If operators never patched after the August 6 advisory, or if attackers had also taken administrative session cookies, API keys, or PostgreSQL dumps, they could simply return in early November and cash out the unpatched NBXplorer hot wallets through the same entry points.
  2. Other pre-2.4.2 authentication and privilege escalation bugs. Between 2.4.2 (August 7) and 2.4.7 (October 29), the BTCPay commit history shows dozens of quiet fixes for serious authentication and multi-tenant escalation bugs that were present in 2.4.1. Anyone reading the public diffs of 2.4.3 through 2.4.7 could build a one-day exploit against nodes still on 2.4.1 without much effort.
  3. An API key scope escape. Before 2.4.6 (October 26, 2026), a flaw in API key permission validation (#7684, fixed by contributor @Kukks) let restricted Greenfield API keys exceed their granted store and user scopes when the key’s owner was a Server Administrator. An attacker who captured a supposedly low-privilege invoice-creation or webhook key belonging to an admin on an older instance could pivot to administrative hot wallet spend endpoints.

How an admin session turns into a drained wallet

To see why the team ordered an immediate ./btcpay-down.sh instead of telling users to flip a setting in the dashboard, trace how a hot wallet sweep works once an attacker holds an admin session token or an unconstrained Greenfield API key. With an active hot wallet, an authenticated administrator has two ways to move funds, and neither needs shell access to the host or SQL injection against the postgres container.

Seed exfiltration through administrative endpoints

If the hot wallet was generated inside BTCPay (or imported with seed backup retention on), the BIP-39 12- or 24-word mnemonic and the HD master private key (xprv) sit in NBXplorer’s metadata vault. An account with ServerAdmin or the btcpay.store.canmodifystoresettings permission can query the seed recovery controller (/stores/{storeId}/onchain/{cryptoCode}/seed) or call NBXplorer’s GetExtKey RPC.

Once one HTTP response returns the cleartext mnemonic or xprv, the state of the server no longer matters. The attacker imports the seed into Electrum or Sparrow on their own machine, builds a transaction spending every confirmed and unconfirmed UTXO at a high fee rate (or using Replace-By-Fee, BIP-125), and broadcasts it to the Bitcoin network directly. Running ./btcpay-down.sh after the seed has been read cannot stop that sweep. It only stops the attacker from reading seeds they have not yet requested.

Automated PSBT construction and signing through HotwalletSafe

Even if seed display is restricted, or the attacker wants to automate the drain across hundreds of compromised instances, the Greenfield API exposes full transaction building and signing. The attacker sends a POST to /api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/transactions with an external destination address, proceedWithBroadcast set to true, and the maximum available balance. Once btcpayserver accepts the request, everything happens in memory on the internal container network:

  1. The WalletController or Greenfield handler checks the session cookie or API key against ASP.NET Core’s AuthorizationService.
  2. BTCPay asks NBXplorer (POST /v1/cryptos/btc/derivations/{derivationStrategy}/psbt/create) to select all spendable UTXOs, calculate weight units, and assemble an unsigned BIP-174 PSBT that pays the balance to the attacker’s scriptPubKey.
  3. HotwalletSafe requests the private key context from NBXplorer (GetExtKey), derives the child private keys (k_i) for each input’s BIP32Derivation path (m/84’/0’/0’/0/i), signs the transaction sighash with ECDSA or Schnorr (BIP-340), finalizes the witness stacks, and serializes the signed raw transaction.
  4. NBXplorer passes the signed hex to bitcoind through the sendrawtransaction RPC, and the sweep enters the global mempool.

To NBXplorer and bitcoind, a theft of the whole treasury looks the same as a routine customer refund. No secondary hardware confirmation, time lock, or out-of-band cosigner is there to reject the odd destination.

BTCPay Server 2.4.2 to 2.4.7: the 12-week hardening sprint and Anthropic’s OSS audit

The stretch from the August 6 LND advisory (2.4.2) to the October 29 emergency release (2.4.7) was the most intense security-hardening cycle in BTCPay Server’s history. The commits and breaking changes across those six releases show how much application-layer attack surface was still open on 2.4.1 installations.

After announcing on August 9 that BTCPay had partnered with outside security researchers, including the Bitcoin Red Team, Project Loupe, Magic Grants, and Anthropic’s frontier OSS Scanner program, the maintainers worked through the legacy trust assumptions in the codebase.

Versions 2.4.3 and 2.4.4: multi-tenant escalation and unsafe defaults

Version 2.4.3 (August 24, 2026) and version 2.4.4 (September 7, 2026) went after privilege escalation and unsafe defaults on shared servers. The team removed the legacy SSH host administration settings from the web app in favor of an isolated btcpay-host integration (#7511, #7543), which closed a path where compromising the web app could lead straight to root shell execution on the host.

They also removed legacy BitPay Basic-auth API keys (#7561), changed Greenfield API key revocation to use key IDs instead of exposing raw secrets (#7561), stopped newly generated API keys from leaking in OAuth and authorization redirect URLs (#7542), and required strict hostname validation before domain configuration changes. To limit lateral movement between stores on shared instances, #7519 made users explicitly accept store invitations instead of being bound silently, and #7514 blocked zero-amount invoices by default and disabled unauthenticated NFC checkout flows.

Version 2.4.5: SSRF blocking and network containment

Version 2.4.5 (October 4 to 6, 2026) focused on network containment and server-side request forgery (SSRF). BTCPay fetches remote metadata and exchange rates and sends webhooks to merchant-defined URLs, so SSRF bugs have historically let attackers with store-level permissions probe internal Docker containers such as http://nbxplorer:32838 or http://127.0.0.1. Version 2.4.5 added strict SSRF blocking and leaner Docker container isolation.

Version 2.4.6: the API key scope fix

Version 2.4.6 (October 26, 2026) fixed high-severity authorization boundary failures. The main one, #7684, corrected restricted Greenfield API keys escaping their store and user permission scopes when the account owner was a server administrator. On any server before 2.4.6, an admin who created a restricted API key for an e-commerce plugin such as WooCommerce or Shopify effectively gave that external store full administrative API authority over the BTCPay instance, hot wallet spend rights included.

Version 2.4.7: 85 findings from Anthropic’s OSS scanner

Version 2.4.7 (October 29, 2026) shipped 72 hours before the hot wallet sweeps began in earnest. It resolved 85 security findings from Anthropic’s automated OSS Scanner, which supplied working exploit reproducers and proposed patches for the C# codebase. By the scanner’s severity ratings, the release fixed 1 critical, 13 high, 52 medium, and 19 low findings.

Among the fixes were a patch against SMTP credential leakage across hostname changes (an attacker with dashboard access could point the SMTP server at a listener they control and trigger a test email to capture the saved plaintext SMTP password) and a patch rejecting integer overflows in cart-line totals and Point-of-Sale (POS) unit prices (#7764).

What the release timeline means for operators

Version 2.4.7 put 85 vulnerability descriptions, commit diffs, and regression tests in a public GitHub repository on October 29. Anyone watching the btcpayserver/btcpayserver commit log got an itemized list of the authentication, permission-scoping, and input-validation flaws in earlier builds. Whether the November attackers used a weaponized diff from the 2.4.2 to 2.4.7 sequence or an older pre-2.4.2 credential cache, any operator still on 2.4.1 was exposed to publicly documented vulnerabilities.

The maintainers’ caution about 2.4.7 is also justified. Static and LLM-assisted scanners like Anthropic’s find localized data-flow bugs, missing permission attributes on controller actions, SSRF sinks, integer overflows, and credential reuse well. They are much less reliable at multi-step architectural state confusion or session token fixation across asynchronous microservices. Until the project publishes the HTTP access logs and call stacks showing how attackers established their administrator sessions on swept servers, operators should not treat 2.4.7 as a guarantee against hot wallet compromise.

Why self-hosted crypto payment servers are risky

The August and November incidents expose a contradiction at the center of self-hosted crypto payment gateways. BTCPay Server became popular because its watch-only xpub design let merchants take checkouts on an untrusted, internet-facing Virtual Private Server (VPS) without risking a single satoshi to theft after the fact. Over four years, demand for automated Lightning routing, instant refunds, pull-payment payroll, and custodial multi-tenant “Uncle Jim” hosting turned it from a stateless invoice watcher into a hot wallet operating system.

Storing an unencrypted xprv in NBXplorer, or an unattenuated admin.macaroon on a shared Docker volume, reduces the security of those keys to that of a large web application stack. Every C# NuGet dependency, Greenfield API route, OAuth redirect handler, and reverse-proxy header rule becomes part of the trusted computing base for your private key. One missing authorization attribute or a subtle flaw in TOTP middleware becomes an irreversible on-chain sweep.

How to secure a self-hosted BTCPay Server after the hot wallet attacks

Passive update habits are not enough in this threat environment. Production operators need strict cryptographic and network compartmentalization.

Rotate keys and move funds if you ran 2.4.1 or earlier

Patching closes a code hole. It does not revoke a secret that was already copied off your disk. If you ran an on-chain hot wallet or an LND node on 2.4.1 or earlier, assume the NBXplorer master seed and LND admin.macaroon may have been exfiltrated during the exposure window, even if you have since moved to 2.4.7. Upgrading in place while leaving funds in the same HD derivation tree lets an attacker who scraped your seed in August sweep it in November.

Generate a new BIP-39 seed on an offline device and sweep all existing UTXOs to the new derivation scheme. Then check that LND macaroons were regenerated (remove the old .macaroon files and restart lnd), including across any external reverse proxies or Tor hidden services.

Replace on-chain hot wallets with watch-only descriptors

Most merchant e-commerce workflows do not need an on-chain hot wallet on the checkout server. Take incoming payments with watch-only xpub or output descriptor schemes whose private keys stay on air-gapped hardware wallets such as Coldcard, Foundation Passport, Jade, or SeedSigner. For refunds or batch payouts, build unsigned PSBTs in BTCPay and sign them locally over WebUSB or SD card with BTCPay Server Vault or an external coordinator like Sparrow Wallet. Never enable savePrivateKeys in NBXplorer.

Cap hot wallet balances and isolate signers

If your business logic requires automated signing, such as an automated swap service or an instant pull-payment dispenser, treat the hot wallet like a cash register till and not a bank vault. Disable PoliciesSettings.AllowHotWalletForAll globally, run the hot wallet on a dedicated instance separate from your main watch-only store server, and set automated sweeping rules that cap the balance at the liquidity needed for 24 hours of operations.

Never create Greenfield API keys under a ServerAdmin account. Make a dedicated unprivileged user scoped to one store’s payout permissions, and bind FIDO2/WebAuthn hardware security keys to every account on the server.

Segment network access to admin and API routes

A payment processor has to expose its public invoice checkout routes (/i/{invoiceId}) and webhook receivers to the internet. Nothing requires exposing /login, /server/, /stores/, or /api/v1/ (Greenfield) to arbitrary IP addresses. Configure the upstream nginx, Cloudflare, or WireGuard edge proxy to limit administrative paths and Greenfield endpoints to a tailnet (Tailscale or WireGuard VPN) or a static corporate IP allowlist. That stops unauthenticated remote authentication bypasses before the request reaches the .NET Kestrel web server.

Bottom line: keep private keys off public servers

The BTCPay maintainers earned credit for transparency. They issued an immediate shutdown alert, brought in outside red teams and Anthropic’s scanning initiative, and funded a 10% recovery bounty (up to 3 BTC) and 0.21 BTC researcher grants from a modest FOSS treasury. Open disclosure still cannot change what bearer cryptography is. Self-hosted payment infrastructure punishes set-and-forget maintenance, and any server holding live private keys on the public internet is one authentication logic bug away from a drained wallet.

Buy me A Coffee!

Support The CyberSec Guru’s Mission

🔐 Fuel the cybersecurity crusade by buying me a coffee! Your contribution powers free tutorials, hands-on labs, and security resources.

Why your support matters:
  • Writeup Access: Get complete writeup access within 12 hours
  • Zero paywalls: Keep the main content 100% free for learners worldwide

Perks for one-time supporters:
☕️ $5: Shoutout in Buy Me a Coffee
🛡️ $8: Fast-track Access to Live Webinars
💻 $10: Vote on future tutorial topics + exclusive AMA access

“Your coffee keeps the servers running and the knowledge flowing in our fight against cybercrime.”☕ Support My Work

Buy Me a Coffee Button

If you like this post, then please share it:

Exploits

Discover more from The CyberSec Guru

Subscribe to get the latest posts sent to your email!

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.