For the exploit to succeed, the RTL application’s password must have been known. This could be trivial in some cases. For example, Umbrel uses a hard-coded password for RTL. Because RTL is simply a one-click install inside Umbrel, it seems likely that many users have left it at that default setting.
The vulnerability was due to the
Access-Control-Allow-Origin HTTP header being set to a value of
*. Simple but deadly.
I contacted the RTL developers directly, who responded within hours and pushed a permanent fix in under two weeks. Umbrel included the patched version immediately after it was released. If you are running RTL version v0.11.0-rc3 or later, you are patched. If not, you should upgrade immediately or risk losing your coins.
Both RTL and Umbrel are fantastic pieces of software that help secure and scale the Bitcoin network. Both teams took this report very seriously and were a pleasure to deal with. This write-up is my own effort to help secure the network and its users, by demonstrating how an attacker might come for your coins and what you can do to stop them.
Security in RTL/Umbrel⌗
Umbrel’s GitHub does state specifically that the software is not secure and not to store funds that you aren’t prepared to lose.
RTL also allows you to set both a strong password and to enable two-factor authentication, both of which you should do. When installed manually, RTL will force the user to set a new password at first logon, which would make this exploit significantly more difficult to execute.
How the exploit works⌗
Here is the proof-of-concept exploit code. It has been renamed to
.txt so that it is safe to click and view. If rendered as part of an HTML document, it will attack your RTL installation and attempt stealing your Bitcoin. If you rename it to
.html and open it in a web browser, you might send me 1000 Satoshis (less than $1 USD), so be careful.
For this write-up, I am using Umbrel (a full-node implementation) as an example. However, the bug was found not in Umbrel itself but in RTL, which is a common add-on.
Umbrel is often installed on a home network, perhaps on something like a Raspberry Pi. By default, it is available at the URL
Let’s say Trinity is at home and using her laptop to browse the Internet. She has a Raspberry Pi running Umbrel on the same network, and it is accessible from her laptop’s web browser. Her firewall does not have any special rules to allow inbound traffic - just a typical home configuration.
Trinity is interested in the Lightning network, so she clicks “Install” on the RTL app inside her Umbrel node’s “App Store” page. The app is now available at
http://umbrel.local:3001 with the default password of
moneyprintergobrrr, as shown in the screenshot below:
At this point, Trinity hasn’t even opened the RTL app to take a look. Merely telling Umbrel to install it is enough to create an exploitable scenario. This is because the RTL application, by default, will have access to any on-chain funds secured in Umbrel’s wallet. It needs this in order to do things like open channels.
- The malicious website instructs Trinity’s browser to perform an HTTP
POSTrequest containing known default credentials to
http://umbrel.local:3001(the RTL default URL in an Umbrel installation).
- “WAIT!” her browser says. “That could be dangerous. Let me first send it an
OPTIONSrequest to see if that is allowed”. This is called a CORS pre-flight request.
- The RTL application sends a response with the HTTP header
- Her browser understands this as permission to allow the malicious website to instruct her browser to send complex commands to RTL.
- The request is sent and RTL responds with a session token.
- The malicious website tells her browser to send another HTTP
POSTrequest to RTL, this time containing the valid session token and instructions to send funds to an attacker-controlled address.
At this point, the transaction has been broadcast and the funds will permanently belong to the attacker as soon as they are included in a new block. This process is shown in the diagram below.
Using the PoC⌗
If you’d like to try it yourself, first ensure that you are running a vulnerable version of RTL. Rename the
poc.txt file to
poc.html and change the following variables:
passwordHash: choose one of the provided defaults or set your own
rtlHost: choose one of the provided defaults or set your own
attackerAddress: leave at default or use your own address
sendAmount: How many sats to send
sendFee: Miner fee (sat/bytes)
Then simply open the file inside your favorite web browser. You might want to watch network inspection as you go, to see what is happening.
In the provided PoC, variables are set to send only a small amount of Bitcoin (1000 Satoshis) to a specific address. However, this could be tweaked to completely empty the wallet. With a bit more coding, it could also be used to interact with Lightning channels or to send funds via a Lightning invoice (probably, I didn’t try).
What we can learn from this⌗
NEVER continue running something with a default password. Enable two-factor authentication wherever you can. Even if the box is “safe” on your home network, assume it can be targeted and protect it accordingly.
Attack surfaces are often much wider than we think. In this write-up, we talk about a system that is hosted on a home network. One might assume that an attacker would first need to breach that home network in order to attack it. However, this is often not the case! We saw here that simply visiting a malicious website from a laptop on the same network was enough to have literal money stolen from that system.
- 31 May 2021: Contacted @RTL_App and @getumbrel on Twitter requesting a secure communication method
- 1 June 2021: Devs from both RTL and Umbrel join a secure chat where full details on vulnerability provided
- 10 June 2021: RTL notifies me of fix in PR https://github.com/Ride-The-Lightning/RTL/pull/700
- 10 June 2021: Tested fix myself, confirmed exploit now blocked due to CORS
- 31 July 2021: Public disclosure