A Bug in Chrome Gives Bad Actors License to Play ‘20 Questions’ with Your Private Data

Private-browsing-data-Chrome-blog

In a 2013 interview with The Telegraph, Eric Schmidt, then CEO of Google was quoted as saying: “You have to fight for your privacy or lose it.”

Five years later, with the ‘Cambridge Analytica’ data breach scandal fresh in our memory, Eric Schmidt’s statement rings as a self-evident truth. Similarly clear today is the nature of the “fight”: a grapple for transparency and corporate accountability that can only be won through individual vigilance.

With this in mind, in this post, we’ll share with you details of a new browser bug we uncovered, which has the potential to affect the majority of web users. With it, bad actors could play a ‘guessing game’ to uncover private data stored on Facebook, Google, and likely many other web platforms.

The bug in question affects all browsers running the Blink engine — used to power Google Chrome –, exposing users who aren’t running the latest version of Chrome. Currently, over 58 percent of the entire internet population uses Google Chrome.

Once the vulnerability was identified, Google patched it in the latest release of Chrome 68; and we strongly recommend that all Chrome users make sure that they’re running the latest version.

Mining Private Data

The bug in question makes use of the Audio/Video HTML tags to generate requests to a target resource.

By monitoring the progress events generated by these requests, it grants visibility into the requested resource’s actual size. As we found out, this information can then be used to “ask” a series of yes and no questions about the browser user, by abusing filtering functions available on social media platforms like Facebook.

For example, a bad actor can create sizeable Facebook posts for each possible age, using the Audience Restriction option, making Facebook reflect the user age through the response size.

The same method can be used to extract the user gender, likes, and many other user properties we were able to reflect through crafted posts or Facebook’s Graph Search endpoints.

Large response size would indicate that the restriction didn’t apply, while small ones would indicate that the content was restricted. Meaning, for instance, that the user is from a disallowed age or gender. With several scripts running at once — each testing a different and unique restriction –, the bad actor can relatively quickly mine a good amount of private data about the user.

In a more serious scenario, the attack script would be running on a site that requires some kind of email registration — an e-commerce or a SaaS site, for instance –. In this case, the above-mentioned practices would allow the bad actor to correlate the private data with the login email address for even more extensive and intrusive profiling.

Attack Flow

When a user visits the bad-actor site, the site injects multiple hidden video or audio tags that request a number Facebook posts the attacker previously published and restricted using different techniques. The attacker can then analyze each request to indicate, for example, the user’s exact age, as it’s saved on Facebook, regardless of their privacy settings.

Discovering the Bug

A few months ago I was researching the Cross-Origin Resource Sharing (CORS) mechanism by checking cross-origin communications of different HTML tags. During my research, I noticed an interesting behavior in the video and audio tags. It seems that setting the ‘preload’ attribute to ‘metadata’ changed the number of times the ‘onprogress’ event was being called in a way that seemed to be related to the requested resource size.

To check my hypothesis, I created a simple NodeJS HTTP server that generates a response in the size of a given parameter. I then used this server endpoint as the resource for the JavaScript shown above.

The script creates a hidden audio element that:

  • Requests a given resource
  • Track the number of times the `onprogress` event was triggered
  • Returns the value of the counter once the audio parsing fails

I started experimenting, requesting different response sizes while looking for a correlation between the size and the number of times the `onprogress` event was triggered by the browser.

As you can see in the graph below, when response size is zero only one `onprogress` event is called, for a response of around 100KB the event is called twice, and the number of events continues to increase, allowing me to estimate the size of most web pages.

From this, we see that the number of `onprogress` events correlates with the size of the response, hence we can indicate whether the restriction criteria was met.

Conclusion

Once we confirmed the vulnerability we reported it to Google with a proof of concept, and the Chrome team responded by patching the vulnerability in Chrome’s 68 release.

We’re delighted to have contributed to protecting the privacy of the entire user community, as we continuously do for our community.