Security Advisory: Upgrade to OnionShare 0.4 Immediately

Yesterday Jacob Appelbaum discovered an input sanitation bug in OnionShare 0.3. It is now fixed, and you should upgrade to the latest version before using it again. You can download the latest version from https://onionshare.org/.

Here’s how the bug worked

The OnionShare GUI is built using webkit, the browser engine that powers Chrome, and written in HTML, CSS, and Javascript. When you open OnionShare and share a file, you get a URL that looks like this:

http://e6hkwn4iyfvoaecu.onion/2hff4jdz7pthbbkfxtighpolpu

If the recipient loaded that exact URL, it displayed “Download page loaded” in the GUI. But if the recipient loaded a different URL at the same Tor hidden service address, such as:

http://e6hkwn4iyfvoaecu.onion/some_other_url

The recipient would receive a 404 error and the OnionShare would display “Other page has been loaded: /some_other_url” to the sender. This string, “some_other_url”, is the input that was not being sanitized. If the recipient loaded:

http://e6hkwn4iyfvoaecu.onion/<script>alert('xss')</script>

Then that piece of Javascript would execute inside the OnionShare GUI on the sender’s computer, and “xss” would pop up in an alert box.

This is a serious vulnerability because the recipient can use it to deanonymize the sender by forcing webkit to load a resource on a website that the attacker controls. This resource will be loaded over the normal internet, not Tor, so the receiver can check their web server log to find the sender’s IP address.

Additionally, I’ve discovered that the version of webkit that comes with Qt4’s QtWebKit framework is scarily old, and doesn’t get automatic webkit updates. It’s possible that there are year-old public webkit exploits could be used by the receiver to not only deanonymize the sender, but escalate to arbitrary code execution.

What is not affected

If an outside attacker monitors the network traffic of either the sender or the receiver, they still couldn’t compromise the file being sent or the anonymity of either party. The attacker in this case must be the receiver (or someone who eavesdropped on the OnionShare URL that was sent, and started making requests to it before the legitimate receiver downloaded it).

How the fix works

OnionShare 0.4 fixes this bug in a couple ways. First, the input is now sanitized, so when the receiver loads:

http://e6hkwn4iyfvoaecu.onion/<script>alert('xss')</script>

It just displays: Other page has been loaded: /<script>alert(‘xss’)</script> and doesn’t actually execute any Javascript.

Additionally, the web server that powers the GUI’s browser now sets the Content-Security-Policy header to default-src ‘self’; connect-src ‘self' . This means that the page will refuse to execute any Javascript that is inline (inside <script> tags), in attributes like onclick or onmouseover, in links like href="javascript:" , etc. It will also refuse to load any resources from any external domain. So in case some other cross-site scripting vulnerability exists, the malicious Javascript won’t execute and the sender won’t be able to be deanonymized.

Future plans

An important future plan for OnionShare is automatic updating for Windows and OSX, and to be included in Linux distro repositories to use the package manager’s automatic updates. Here’s the issue on GitHub, but for now users have to update manually.

At first it seemed like using webkit to build desktop app GUIs was excellent. It makes it quick and simple to deploy powerful, featureful, HTML5-based desktop programs. But considering potential bugs like this one, and that the version of webkit that ships with GUI libraries like Qt and GTK are abysmally old and don’t get security updates, it now seems like this is a bad way of building secure software. I plan on rebuilding the OnionShare GUI using pure Qt widgets, and not including webkit at all. This will dramatically decrease the client-side attack surface. Here’s the issue on GitHub.

When you’re using OnionShare in Tails there is an additional risk. You’re required to run it as the root user because it needs to open a hole in the local firewall (this will no longer be necessary when we remove webkit), and only the root user in Tails can connect to the Tor control port to start a new hidden service. It would be much better if OnionShare ran as the unprivileged amnesia user, and a separate root processes was started just for the specific tasks that require root. Here’s the issue on GitHub.