How I found a TOR vulnerability in Brave Browser, reported it, watched it get patched, got a CVE (CVE-2020-8276), and a small bounty all in one working day

Recently, I discovered a small but potentially devastating vulnerability in the new Tor feature of the Brave browser.

As of November 2nd 2020, Brave monthly users have massively increased their browser market share to 20 Million Monthly Active Users + 7 Million Daily Active Users.

Brave is a unique browser, created by Brendan Eich, who is also the inventor/creator of JavaScript. He is also the former CEO of the Firefox browser’s parent company, Mozilla.

Brave is based on Chromium, which is the Open Source version of the well known Chrome browser. Being an Open Source project, this allows any developer, anywhere, the ability to inspect the source code of the project. You can inspect the code yourself here: GitHub - brave/brave-core: Core engine for the Brave browser for Android, Linux, macOS, Windows. For issues https://github.com/brave/brave-browser/issues

On Oct 5, 2020, Brave added the ability to integrate Tor sessions into their Incognito mode. Essentially, it is Private Window browsing inside Chrome, with an added Tor network traffic routing circuit, for a whole range of added privacy bonuses.

A few weeks later, on October 30th, I updated my local version of Brave to the latest version.

Specifically, I was running brave-bin 1:1.16.72-1, from the Arch User Repository (AUR) btw. https://aur.archlinux.org/packages/brave-bin/

After some light digging, there is a transient session information file located in the folder that contains your Brave configurations.

~/.config/BraveSoftware/Brave-Browser/Local\ State

The file is named “Local State” and annoying has a space in the filename, so you must always quote the file or escape the space with a backslash.

It is a JSON file that stores core metrics, particularly, the feature in which Brave makes money from.

Without going into too much detail, Brave makes money off users enabling the Brave rewards program that involves cryptocurrency, sponsored background images, and referral links to big crypto trading sites like Binance, Gemini, Crypto.com, Coinbase etc.

brave-json-blob-Local-State.png

Once pretty printed, you can see the sites in which Brave will send a “partner” header to:

    "referral": {
      "headers": [
        {
          "cookieNames": [],
          "domains": [
            "coinbase.com",
            "api.coinbase.com"
          ],
          "expiration": 31536000000.0,
          "headers": {
            "X-Brave-Partner": "coinbase"
          }
        },
        {
          "cookieNames": [],
          "domains": [
            "softonic.com",
            "softonic.cn",
            "softonic.jp",
            "softonic.pl",
            "softonic.com.br"
          ],
          "expiration": 31536000000.0,
          "headers": {
            "X-Brave-Partner": "softonic"
          }
        },
        {
          "cookieNames": [],
          "domains": [
            "marketwatch.com",
            "barrons.com"
          ],
          "expiration": 31536000000.0,
          "headers": {
            "X-Brave-Partner": "dowjones"
          }
        },
        {...

If you visit these websites while using Brave Browser, the browser will automatically add a referral header. This is the same as clicking an affiliate link to Amazon, except that you can’t really turn it off.

You can modify the source code, of course, but below I will demonstrate the difference and why it initially raised my eyebrows…

Here is the request for a normal website:

curl 'https://disclose.io/' \
  -H 'authority: disclose.io' \
  -H 'pragma: no-cache' \
  -H 'cache-control: no-cache' \
  -H 'dnt: 1' \
  -H 'upgrade-insecure-requests: 1' \
  -H 'user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36' \
  -H 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' \
  -H 'sec-fetch-site: none' \
  -H 'sec-fetch-mode: navigate' \
  -H 'sec-fetch-user: ?1' \
  -H 'sec-fetch-dest: document' \
  -H 'accept-language: en-US,en;q=0.9' \
  -H 'sec-gpc: 1' \
  --compressed

Here is the request for a Brave Partner website:

curl 'https://www.coinbase.com/' \
  -H 'authority: www.coinbase.com' \
  -H 'pragma: no-cache' \
  -H 'cache-control: no-cache' \
  -H 'dnt: 1' \
  -H 'upgrade-insecure-requests: 1' \
  -H 'user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36' \
  -H 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' \
  -H 'x-brave-partner: coinbase' \
  -H 'sec-fetch-site: none' \
  -H 'sec-fetch-mode: navigate' \
  -H 'sec-fetch-user: ?1' \
  -H 'sec-fetch-dest: document' \
  -H 'accept-language: en-US,en;q=0.9' \
  -H 'sec-gpc: 1' \
  --compressed

As you can see, Brave inserts the header:

  -H 'x-brave-partner: coinbase' \

Obviously Brave has to make money. But I immediately wanted to see if it showed up on Tor sessions.

To enable the Tor feature, you need to visit brave://settings/?search=tor, or just go to settings in the menu.

Enable this:

Private Window with Tor
Tor hides your IP address from the sites you visit.

Once enabled, you can open Tor windows in the menu bar:

open-tor-window-brave.png

As Tor Project users will understand, there are a number of obvious issues while using Tor outside of the original Tor Browser.

The list of ongoing leakproofing issues for the Brave Tor experience can be found in the Brave Core git issues: Issues · brave/brave-browser · GitHub

Tor browser users know about the window size fingerprinting technique, which already has an issue opened for the Brave rendition of Tor: [hackerone] fix tor window size fingerprinting · Issue #9341 · brave/brave-browser · GitHub

To answer the question above, yes, Brave sends the “x-brave-partner: coinbase” header when visiting the coinbase website.

Even when Tor is on:

curl 'https://www.coinbase.com/' \
  -H 'authority: www.coinbase.com' \
  -H 'pragma: no-cache' \
  -H 'cache-control: no-cache' \
  -H 'dnt: 1' \
  -H 'upgrade-insecure-requests: 1' \
  -H 'user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36' \
  -H 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' \
  -H 'x-brave-partner: coinbase' \
  -H 'sec-fetch-site: none' \
  -H 'sec-fetch-mode: navigate' \
  -H 'sec-fetch-user: ?1' \
  -H 'sec-fetch-dest: document' \
  -H 'accept-language: en-US,en;q=0.9' \
  --compressed

I reported this small issue to the security team at Brave, via email, rather than HackerOne.

Along with this issue, I mentioned to the team that there is a folder that is generated during Tor sessions:

~/.config/BraveSoftware/Brave-Browser/tor/data/keys
~/.config/BraveSoftware/Brave-Browser/tor/data/state
~/.config/BraveSoftware/Brave-Browser/tor/data/tor.log
~/.config/BraveSoftware/Brave-Browser/tor/data/cached-microdescs.new
~/.config/BraveSoftware/Brave-Browser/tor/data/cached-microdesc-consensus
~/.config/BraveSoftware/Brave-Browser/tor/data/cached-certs
~/.config/BraveSoftware/Brave-Browser/tor/data/lock

I suggested to the Brave security team that they should clear or shred this folder on exit.

Brave has a super responsive security team that excellently run by a well-known security icon named Yan Zhu, who you can follow on Twitter here: https://twitter.com/bcrypt

This is the original security report in full:

# Re: [Security]
### Vulnerability Details
A vulnerability in the Brave Web Browser allows remote websites to bypass an intended privacy feature of the Brave Web Browser. Even while using Tor, Brave sends a referral partner HTML header to specific partner websites, for example, "X-Brave-Partner": "coinbase", and "X-Brave-Partner": "softonic".

A targeted attack could trivially de-anonymize a user of the Brave browser. Since Oct 5, 2020 Brave offers a "private window" feature that supports The Onion Router (Tor) Network. The purpose of the Tor Browser from Tor project is to isolate each website you visit so that third-parties cannot follow you.

The Brave private window feature with Tor does not sufficiently anonymize users visiting Brave's partner websites.

While using Tor, Brave stores the count, attempt count, and absolute timestamp of the above HTML request:
"tor_used": true
"referral_attempt_count": 25,
"referral_attempt_timestamp": "13248492282530685",
"timestamp": "13244344644287168"
"incognito_used_timestamp": "13248493693576042",
"last_used": "Tor Profile",
"profile_counts_reported": "13248492279614953"

After the user ends the Tor session, the data is not cleared and users should be aware that the Tor feature of Brave browser is not secure as intended and the browser can leak, or send usage statistics, of critical information to their partner websites that could be used by an attacker to triangulate a user.

After a few emails back and forth discussing the issue with the persistent Tor folder and various Tor metrics in the Local State file, Yan @ Brave confirmed in the following message:

Monday Morning, 2nd November 2020:

# Re: [Security]
...we found that indeed we were accidentally logging the when *any* incognito session was used, when we were supposed to only log the timestamp that a non-Tor incognito session was used: https://github.com/brave/brave-core/pull/7010. 

We consider this a valid security issue and would be happy to issue a bounty via HackerOne if you resubmit it there: https://hackerone.com/brave. I think this is a sec-low issue given that someone who has access to the local disk cannot tell if the timestamp corresponds to a Tor session (rather than a regular incognito session). Also, the value that actually gets sent to the Brave metrics server is bucketed into the following values (so the timestamp isn't a fingerprinting vector):

Used in last 24h
Used in last week but not 24h
Used in last 28 days but not week
Ever used but not in last 28 days
Never used

Before I had even submitted the report to HackerOne, the team had already patched the vulnerability:

GitHub has an amazing feature where you can add .patch to a pull request URL and it will give you the Pull Request changes, in a patch file.

https://github.com/brave/brave-core/pull/7010.diff

From 2b690a354e42ee8cd2aaa9a7f0b4375dc91d5e01 Mon Sep 17 00:00:00 2001
From: Ivan Efremov <iefremovXbrave.com>
Date: Mon, 2 Nov 2020 15:43:05 +0700
Subject: [PATCH] 12452: Fix incognito used timestamp for P3A.

Fixes https://github.com/brave/brave-browser/issues/12452
---
 browser/p3a/p3a_core_metrics.cc | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/browser/p3a/p3a_core_metrics.cc b/browser/p3a/p3a_core_metrics.cc
index 9befca08bf6..4a0c2d691d9 100644
--- a/browser/p3a/p3a_core_metrics.cc
+++ b/browser/p3a/p3a_core_metrics.cc
@@ -43,7 +43,8 @@ enum class WindowUsageStats {
 };
 
 const char* GetPrefNameForProfile(Profile* profile) {
-  if (profile->IsIncognitoProfile()) {
+  if (profile->IsIncognitoProfile() &&
+      !brave::IsTorProfile(profile)) {
     return kLastTimeIncognitoUsed;
   }
   return nullptr;

It’s hard to follow the timestamps correctly, because there are lots of timezones and stamps involved, but the speed at which this was fixed can be emphasized by the following fact:

In the reply where Brave confirmed it was indeed a security issue, they had already patched the vulnerability.

I would like to thank Brave security for being crystal clear in all emails, very open and discussive about security issues, and for the quick turn around.

Had this not been over the weekend, I think Brave would have patched and pushed this fix same-day.

Open Source Code Programs

I speak to a lot of security researchers, every day.

Mostly on my Twitter @sickcodes, sometimes on Discord, and also researcher forums like here, https://community.disclose.io.

For other researchers out there, I’d just like to highlight a few things about this disclosure process.

This bug is an Open Source Code program on HackerOne, and you can find the Brave project’s HackerOne program here: HackerOne

Although Brave is designed for Desktops, there are plenty of security programs out there that are meant to run on servers.

The reason I reported the vulnerability through email first, was that I wasn’t really interested in the bounty, I was interested in the CVE.

What actually ended up happening was that MITRE rejected the CVE Request, which is at the top of this post, due to some flaws. They actually contacted Brave first to verify the report which was interesting.

After brainstorming with Brave through email, the bug was actually chiseled out to be the core_p3a_metrics timestamping in the JSON file.

What I would like to show other researchers is that this bug involved no actual code review.

Because this is an Information Exposure vulnerability, it is contextual rather than seeing an XSS alert show up on your screen.

One major advantage of Open Source projects is that there are no duplicates.

When a bug is found, usually within a day or two, there is either a Pull Request, that anyone can view, or a new issue posted, that anyone can view publicly.

If you’re having trouble with duplicates, see if.

Even though a simple timestamp might not appear to be a vulnerability, with some critical thinking, you can imagine some scenarios.

For example, consider this scenario

  • a Human Right’s activist has their disk seized by local authorities.
  • Brave browser’s Local State file is read
  • file shows the last time Tor was used, with nanosecond accuracy.
  • the ISP also has a corresponding timestamp for the person’s Tor usage.

As you can imagine, this could be absolutely devastating for some.

Since this is a physical access vulnerability, the actual exploitability is quite low.

While I consider it medium loss of software integrity on the CVSS calculator, I didn’t want to hype this vulnerability up.

I entered the vulnerability as low security and was awarded a bounty of $100

Here are some Critical Weaknesses I encourage other researchers to consider when looking for bugs, like in programs that they use every day:

  • CWE-200: Information Exposure
  • CWE-201: Information Exposure Through Sent Data
  • CWE-202: Exposure of Sensitive Data Through Data Queries
  • CWE-203: Information Exposure Through Discrepancy
  • CWE-209: Information Exposure Through an Error Message
  • CWE-211: Information Exposure Through Externally-Generated Error Message
  • CWE-212: Improper Cross-boundary Removal of Sensitive Data
  • CWE-213: Intentional Information Exposure
  • CWE-214: Information Exposure Through Process Environment
  • CWE-215: Information Exposure Through Debug Information
  • CWE-226: Sensitive Information Uncleared Before Release
  • CWE-497: Exposure of System Data to an Unauthorized Control Sphere
  • CWE-524: Information Exposure Through Caching
  • CWE-526: Information Exposure Through Environmental Variables
  • CWE-532: Information Exposure Through Log Files
  • CWE-538: File and Directory Information Exposure
  • CWE-598: Information Exposure Through Query Strings in GET Request
  • CWE-612: Information Exposure Through Indexing of Private Data

I’m always happy to chat to researchers, and even collaborate, on vulnerabilities together.

There’s only so many hours in each day and more than one brain is almost always stronger than one.

Hope this shed some light on this simple process of finding this vulnerability.

In essence:

  • Thinking about Brave partners made me look at the partner headers.
  • Looking at partner headers in Tor made me look inside the Tor folder.
  • After exiting the Tor folder, and observing no deletion of the folder, I considered this a vulnerability starting block.
  • Further looking inside the .config led me to find Tor timestamps.
  • Since Tor is a security feature, any bugs in security features are bigger than they might seem.

If you want to ask me any questions about finding bugs, or hacking in general, you can follow me on Twitter, my username there is and the URL is:

@sickcodes

https://twitter.com/sickcodes