Chrome extensions and user fingerprint via XSLeaks

Tldr: I found a way for websites to fingerprint whether the visitor has installed a specific extension or not via a trick in XSLeaks. Below is my exciting journey.

Brief for Chrome Extension

For who didn’t know, Chrome extensions can be viewed by going to chrome://extensions/, after turning on Developer mode, the ui should looks like: extension-ui

See those ID ghbmnnjooekpmoecnnnilnnbdlolhkhi, aapbdbdomjkkjkaonfhkkikfgjllcleb, onnfghpihccifgojkpnnncpagjcdbjod ?

We could look into their source by navigate to C:\Users\%USERNAME%\AppData\Local\Google\Chrome\User Data\Default\Extensions.

Any Chrome Extension MUST have 1 file manifest.json at the root of the project. This file describes how Chrome should parse and run the source code: where’s the icons, which js file to load as background, version of extension ? Look more here.

While walking through the doc, I noticed something interesting in web accessible resources section.

Web accessible resources

Here is the documentation for web accessible resources, there’s one paragraph that states:

Prior to Manifest V2 all resources within an extension could be accessed from any page on the web. This allowed a malicious website to fingerprint the extensions that a user has installed or exploit vulnerabilities (for example XSS bugs) within installed extensions. Beginning with Manifest V2, access to those resources was limited to protect the privacy of users. Manifest V2 extensions exposed only those resources explicitly designated as web accessible.

Due to the the amazing of linguistic and my bad english, the way I understood the above paragraph is that:

Before Manifest version 2, any websites could fingerprint which extension the user has installed. In other words, if the extension is using Manifest version before 2, website A could know that the visitor has installed Google Translate extension or not, or any extension that is listed on the marketplace. However from version 2 and above, web accessible resources prevent this “privacy” problem.

By interpreting the paragraph like above, it starts itching my curiousity, so I quickly spin up my local test to find out.

Testing web accessible resources

The target extension that I was testing is Google Translate version 2.0.12. I noticed the ID: aapbdbdomjkkjkaonfhkkikfgjllcleb on my machine so I tried asking my friends if their Google Translate 2.0.12 also has the same ID, to my surprise their ID is the same as mine.

Thus, any machine that has installed Google Translate 2.0.12 could use Chrome and go to the URL: chrome-extension://aapbdbdomjkkjkaonfhkkikfgjllcleb/manifest.json to view the manifest file because the extension ID is the same for everyone. I also did try the same for Firefox but on Firefox the extension ID is generated randomly for each installation.

Firstly, I tried to open new Chrome tab and type following onto the URL bar: data:text/html,<iframe src="chrome-extension://aapbdbdomjkkjkaonfhkkikfgjllcleb/manifest.json">. Immediately I noticed error: Denying load of chrome-extension://aapbdbdomjkkjkaonfhkkikfgjllcleb/manifest.json. Resources must be listed in the web_accessible_resources manifest key in order to be loaded by pages outside the extension..

Then, trying payload data:text/html,<iframe src="chrome-extension://aapbdbdomjkkjkaonfhkkikfgjllcleb/options.html"> actually loads up the options.html page of the extension without any error.

Ah, so the web accessible resource is an allow list websites to reference via iframe or other kind of action (I’ll dig to this later).

Hold up, looking at error event and successful event, I immediately think of 1 more puzzle.

XSLeaks error event

Look more here

The XSLeaks error event trick allow a website to send a request and indicate whether the response is error or success. What if I could run check whether chrome-extension://aapbdbdomjkkjkaonfhkkikfgjllcleb/options.html exists ? Does this mean that my website could fingerprint whether the user has installed Google Translate 2.0.12 ? Let’s find out at:

Turns out it is a known issue by Chromium team and they’re already fixing this issue in upcoming Manifest version 3. In the end, it was only me interpreting the documentation sentence into wrong meaning. The document didn’t clearly said that Manifest version 2 mitigated the fingerprint issue, they just say that Manifest V2 extensions exposed only those resources explicitly designated as web accessible..

Anyway, it was a fun experience.

Chromium report: