← All playbooks
CriticalExploit · 2026-11-03

Attackers drain BTCPay Server hot wallets on version 2.4.1 and older

SockAnalyst · Security+ certified analyst.

What happened

BTCPay Server says attackers stole Bitcoin and Litecoin from hot wallets (wallets whose spending keys sit on the server) on servers running 2.4.1 or earlier. They used a new method to exploit the vulnerability fixed in 2.4.2 back in August. The first known drain was Nov 1 at 13:46 UTC. BTCPay warned users to shut down servers, and hosting providers including LunaNode took instances offline as a precaution.

Who's affected

Merchants and operators self-hosting BTCPay Server 2.4.1 or older with a hot wallet. BTCPay says it has seen no impact on servers already on 2.4.2 or later before its Nov 1 warning, and wallets with keys held off the server (like hardware wallets) weren't drained.

✅ Fix / patch

  • On 2.4.1 or earlier, don't just update: sweep remaining hot-wallet funds to a brand-new wallet with a new seed, made on a trusted device.
  • Take the old server offline (keep its logs), build a fresh VM with the latest BTCPay release, and don't restore the old server onto it.
  • From a trusted device, rotate every credential the old server could reach: hosting, SSH, app, API and Lightning keys.

🔎 Quick hunt check

Check your hot wallet's outgoing transactions since Nov 1 for payments to the reported addresses bc1p0f7wmcnesrapznymf9ljdn04pudgmh96sqtrm9vmgqxdh666fh8qvn63r7 (Bitcoin) or ltc1qp49tmfdueyaqrmgrx0uyx4uegyygt8yt02whee (Litecoin). An unchanged balance doesn't prove you're clean. Report incidents to [email protected].

MITRE ATT&CK: T1190, T1078, T1657

IOCs

  • Wallet addresses: bc1p0f7wmcnesrapznymf9ljdn04pudgmh96sqtrm9vmgqxdh666fh8qvn63r7 (BTC), ltc1qp49tmfdueyaqrmgrx0uyx4uegyygt8yt02whee (LTC)

Hunt queries

Starting points built only from published indicators. Field names vary; tune before use.

index=* ("bc1p0f7wmcnesrapznymf9ljdn04pudgmh96sqtrm9vmgqxdh666fh8qvn63r7" OR "ltc1qp49tmfdueyaqrmgrx0uyx4uegyygt8yt02whee"
 OR (sourcetype=docker* container_name="*btcpayserver*" ("Login" OR "/login" OR "/server/users")))
| stats count min(_time) as first max(_time) as last by host, sourcetype, src_ip
let wallets = dynamic(["bc1p0f7wmcnesrapznymf9ljdn04pudgmh96sqtrm9vmgqxdh666fh8qvn63r7","ltc1qp49tmfdueyaqrmgrx0uyx4uegyygt8yt02whee"]);
union isfuzzy=true
 (Syslog | where SyslogMessage has_any (wallets) or (ProcessName has "btcpay" and SyslogMessage has_any ("Login","/server/users"))),
 (ContainerLogV2 | where ContainerName has "btcpay" and (LogMessage has_any (wallets) or LogMessage has "Login"))
| project TimeGenerated, Computer, ProcessName, SyslogMessage, LogMessage

See all hunt queries →

⏱ CISA deadline

Not in CISA KEV as of Nov 14, 2026.

Sources

Related playbooks

Get the Weekly KEV & Hunt Pack free — plus the daily SOC brief.

Weekly email; daily brief on the website.

Subscribe free

Read the free weekly pack →