Ride The Lightning (RTL) is a web application for managing Bitcoin Lightning Network operations. It is integrated into many popular Bitcoin full-node implementations, such as Umbrel.

In May of 2021, I discovered that malicious JavaScript on a remote website could silently contact a user’s local RTL installation and steal any funds secured by the node’s wallet. In practice, this meant that simply visiting an infected website while having RTL somewhere on your local network could have resulted in your Bitcoin being instantly stolen.

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 http://umbrel.local which can be discovered over the LAN. This is important as having a known URL makes it easy for attackers to cast a wide net with their malicious JavaScript.

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:

App Store Screenshot

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.

Trinity browses a Bitcoin forum searching for info about RTL. She sees a post by “Agent Smith”, titled “How to secure your RTL install on Umbrel”. She clicks the link and begins to read the blog. She is totally unaware that the site contains malicious JavaScript that begins to execute silently in the background.

The JavaScript does the following:

  1. The malicious website instructs Trinity’s browser to perform an HTTP POST request containing known default credentials to http://umbrel.local:3001 (the RTL default URL in an Umbrel installation).
  2. WAIT!” her browser says. “That could be dangerous. Let me first send it an OPTIONS request to see if that is allowed”. This is called a CORS pre-flight request.
  3. The RTL application sends a response with the HTTP header Access-Control-Allow-Origin: *.
  4. Her browser understands this as permission to allow the malicious website to instruct her browser to send complex commands to RTL.
  5. The request is sent and RTL responds with a session token.
  6. The malicious website tells her browser to send another HTTP POST request 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.

Attack Diagram

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

Developers - always test cross origin resource sharing! Electrum learned this lesson back in 2017.

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.

Disclosure timeline

  • 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
  • 10 June 2021: Tested fix myself, confirmed exploit now blocked due to CORS
  • 31 July 2021: Public disclosure