Written by Konark Modi.
In this article, I’ll discuss details of a bug I discovered with Mozilla Firefox private browsing mode that made it possible for private browsing sessions to be tracked.
The features offered might differ from one browser to another, but at the very least a user using private browsing has the two most basic requirements:
1. Websites visited in private cannot save any data
2. Visited pages are not saved
Well, I discovered that the Firefox browser Private browsing mode didn’t meet any of the above requirements.
For a website to track a user across private browsing sessions, it needs to use some persistent storage at the browser level.
I recently came across IndexedDB storage.
IndexedDB is a low-level API for client-side storage of significant amounts of structured data, including files/blobs - Mozilla Developer Network
Although, as per the documentation, IndexedDB should not be available in private browsing mode.
If you use IndexedDB directly on the webpage, it will throw an error:
But what happens if you combine IndexedDB with Web Workers?
Web Workers makes it possible to run a script operation in background thread separate from the main execution thread of a web application - Mozilla Developer Network
Issue Details: The Fallout
IndexedDB can be accessed in private browsing mode via Web Workers. Not only that, but when the browser is closed, the IndexedDB data is not cleared. This stored data will persist across multiple private browsing sessions because it is not cleared when exiting. 😮
So let’s look at a few ways this issue could be abused.
A malicious website can leverage IndexedDB and track users across private browsing sessions. For example, say you visited badsite.com, which uses Web Workers and IndexedDB in private browsing mode. Close the private browsing window, close Firefox, start Firefox again, start private browsing mode, and again visit badsite.com. The website will be able to access the data from your previous private browsing session, as the data is still stored in IndexedDB.
Let’s assume siteA.com loads an analytics script from BadAnalyticsSite.com. Then another website, siteB.com, also loads an analytics script from the same website BadAnalyticsSite.com. Since the malicious website BadAnalyticsSite.com uses Web Workers and IndexedDB, the website BadAnalyticsSite.com can now track users of websites siteA.com and siteB.com across all their private browsing sessions.
IndexedDB adheres to a same-origin policy, which means that every database has a name that identifies it within an origin. Because domain name is used as part of the file name, this can result in serious issues when used in private mode.
For example, if a user visits a test webpage (demo) which uses Web Workers + IndexedDB hosted on cdn.cliqz.com, and loads a resource from konarkmodi.github.io, the following two entries are created on disk.
Because of the above flaw, a website/tracker could effectively generate a fingerprint and save it. Even if a user were to clear the website history or select the option “forget about this site,” the IndexDB storage is not removed. This can create a permanent storage for a website or a tracker that can be leveraged forever.
Report and Fixes
Mozilla encourages security research for their products. In their own words:
The Mozilla Client Security Bug Bounty Program is designed to encourage security research in Mozilla software and to reward those who help us create the safest Internet software in existence.
I reported this issue in October 2017 via their Bug Bounty Program, and the issue was fixed in November 2017. They were prompt to identify and fix the issues.
For more details, you can read the complete bug report at Mozilla’s Bugzilla.
I really appreciate Mozilla’s efforts and actions in fixing issues with the highest priority when it comes to the privacy of its users.
You can follow me on Twitter at Konark Modi
Thanks for reading and sharing ! :)
If you liked this story, feel free to 👏👏👏 a few times (Up to 50 times. Seriously).
I found a major flaw in Mozilla’s private browsing mode — and got them to fix it. was originally published in freeCodeCamp on Medium.