RCE in Tailscale, DNS Rebinding, and You [CVE-2022-41924] ($10,000 USD)

We discussed this vulnerability during Episode 171 on 28 November 2022

A number of bugs in Tailscale leading to an RCE chain.

So many bugs its hard to know where to start on this one. There are a few APIs of interest here:

  • The LocalAPI on Windows this runs on localhost, on Linux its a unix socket. Can do a number of things from here including disclosing the user’s tailscale private key (can be used for impersonation), but for this chain, the important thing is that you can change the current user’s control plane url. Pointing its control plane to an attacker controller server if an attacker could gain access to this API.
  • Quad100 ( doesn’t do much but it discloses some user information like username, and their “tailnet” ip address, allowing one to determine the IP of their PeerAPI.
  • PeerAPI - This API is running on the “tailnet” and should be exposed. It has an endpoint that can be used to share a file with the client. The fail can be PUT using the exposed PeerAPI but then is downloaded by the local GUI using the LocalAPI

So with that background now a couple chains, first both the LocalAPI and PeerAPI could be reachable through DNS rebinding. There are some constraints on reaching the LocalAPI since it is on a private IP when the victim is using Chrome but other than the browser protections it is vulnerable to be accessed through a rebinding attack. So as the first RCE chain, an attacker could have their website, rebind to access LocalAPI from there change the control plane url, enable TailDrop to share a binary, upload a binary onto the victim using TailDrop and have trigger that binary to be executed from the control plane server.

The second chain is a bit more complex, but starts with with rebinding to access Quad100, using that to find where to rebind again to access the PeerAPI. With access to PeerAPI they could cause an XSS in the LocalAPI context. Recall how the GUI would fetch the uploaded file through the LocalAPI, in fetching the file from the LocalAPI it would be served with Content-Type: text/html. So if the attacker side included the LocalAPI endpoint to this uploaded file, it any JavaScript would be executed in the LocalAPI context, allowing for the core attack of the first chain to be followed. There was a catch though, the GUI would fetch the file and delete it from its temprary position that was served by the LocalAPI. However this was defeated by having multiple requests upload the same file, in their racing to control the file, some would fail and the file would never get deleted.