On Firefox, web accessible resources are available at "moz-extension://<extension-UUID>/myfile.png" <extension-UUID> is not your extension's ID. This ID is randomly generated for every browser instance. This prevents websites from fingerprinting a browser by examining the extensions it has installed. https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/Web...
Doesn't the idea of swapping extension specific IDs to your browser specific extension IDs mean that instead of your browser being identifiable, you become identifiable?
I mean, it goes from "Oh they have X, Y , and Z installed" to "Oh, it's jim bob, only he has that unique set of IDs for extensions"
Skimming the list, looks like most extensions are for scraping or automating LinkedIn usage. Not surprising as there's money to be made with LinkedIn data. Scraping was a problem when I worked there, the abuse teams built some reasonably sophisticated detection & prevention, and it was a constant battle.
In order to create the data source that LinkedIn's extension-fingerprinting relies on to work, someone (at LinkedIn*?) almost certainly violated the Chrome Web Store TOS—by (perversely*) scraping it.
* if LinkedIn didn't take the data from an existing data source
"The code" here you're referring to (fetch_extension_names.js[1]) isn't and doesn't claim to be LinkedIn's fingerprinting code. It's a scraper that the researcher behind this repo wrote in order to themselves create the CSV that they're publishing.
LinkedIn's fingerprinting code, as the README explains, is found in fingerprint.js[2], which embeds a big JSON literal with the IDs of the extensions it probes for. (Sickeningly enough, this data starts about two-thirds of the way through the file* and isn't the culprit behind the bulk of its 2.15 MB size…)
* the one (on line 34394) starting:
const r = [{
id: "aacbpggdjcblgnmgjgpkpddliddineni",
file: "sidebar.html"
I mean, regardless of who they are or even if you don’t like what LinkedIn does themselves with the data people have given them, the random third parties with the extensions don’t additionally deserve to just grab all that data too, do they?
> This repository documents every extension LinkedIn checks for and provides tools to identify them.
I get that the CSV lists the extensions, and the tools are provided in order to show work (mapping IDs to actual software). But how was it determined that LinkedIn checks for extensions with these IDs?
Technical writeup from a few weeks ago by a vendor that explains how LinkedIn does it, then boasts that their approach is "quieter, harder to notice, and easier to run at scale":
I didn't find popular extensions like uBlock or other ad blockers.
The list is full of scammy looking data collection and AI tools, though. Some random names from scrolling through the list:
- LinkedGPT: ChatGPT for LinkedIn
- Apollo Scraper - Extract & Export Apollo B2B Leads
- AI Social Media Assistant
- LinkedIn Engagement Assistant
- LinkedIn Lead Magnet
- LinkedIn Extraction Tool - OutreachSheet
- Highperformr AI - Phone Number and Email Finder
- AI Agent For Jobs
These look like the kind of tools scummy recruiters and sales people use to identify targets for mass spamming. I see several AI auto-application tools in there too.
Fingerprinting. There are a few reasons you'd do it:
1. Bot prevention. If the bots don't know that you're doing this, you might have a reliable bot detector for a while. The bots will quite possibly have no extensions at all, or even better specific exact combination they always use. Noticing bots means you can block them from scraping your site or spamming your users. If you wanna be very fancy, you could provide fake data or quietly ignore the stuff they create on the site.
2. Spamming/misuse evasion. Imagine an extension called "Send Messages to everybody with a given job role at this company." LinkedIn would prefer not to allow that, probably because they'd want to sell that feature.
Another thing... they alter the localStorage & sessionStorage prototype, by wrapping the native ones with a wrapper that prevent keys that not in their whitelist from being set.
I’m probably on the list. I made a LinkedIn Redactor that allowed you to add keywords and remove posts from your thread that included such words. It’s the X feature but for LinkedIn. Anyway, got a cease and desist from those lame fucks at LI. So I removed from the chrome store but it’s still available on GitHub.
I'm not sure how you'd patch that. Any request that’s made from the current open tab / window is made on behalf of the user. From my point of view, it's impossible for the browser to know, if the request is legit or not.
Is there no browser setting to defend against this attack? If not, there should be, versus relying on extension authors to configure or enable such a setting.
How do you patch it? The extensions themselves (presumably) need to access the same web accessible resources from their content scripts. How do you differentiate between some extension’s content script requesting the resource and LinkedIn requesting it?
If this is true, it's insane that this would work:
- why does CWS respond to cross-site requests?
- why is chrome sending the credentials (or equivalent) in these requests?
- why is the button enabled server-side and not via JS? Google must be confident in knowing the exact and latest state of your installed extensions enough to store it on their servers, I guess
It's not true. The person you're responding to has a habit of posting implausible-but-plausibly-plausible nonsense, and that's not how this works at all.
Isn't it enumerating web_accessible_resources? Below static collectFeatures(e, t) there is a mapping of extension IDs to files in the const r (Minified JS, obviously.)
Looks like Firefox is immune.
This works by looking for web accessible resources that are provided by the extensions. For Chrome, these are are available in a webpage via the URL chrome-extension://[PACKAGE ID]/[PATH] https://developer.chrome.com/docs/extensions/reference/manif...
On Firefox, web accessible resources are available at "moz-extension://<extension-UUID>/myfile.png" <extension-UUID> is not your extension's ID. This ID is randomly generated for every browser instance. This prevents websites from fingerprinting a browser by examining the extensions it has installed. https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/Web...
And they said that using a browser with sub-5% market share would cause us to miss out on the latest and greatest in web technology!
chrome was made by ex-firefox devs, chrome is still not as good!
This is probably a naive question, but...
Doesn't the idea of swapping extension specific IDs to your browser specific extension IDs mean that instead of your browser being identifiable, you become identifiable?
I mean, it goes from "Oh they have X, Y , and Z installed" to "Oh, it's jim bob, only he has that unique set of IDs for extensions"
It's not a naive question. This comment says it's not possible to do that: https://news.ycombinator.com/item?id=46905213
1 reply →
Maybe, but how long are the extension ids? And if they are random, how long to scan a trillion random alphanumeric ids, to find matches?
I presume the extension knows when it wants to access resources of its own. But random javascript, doesn't.
1 reply →
Skimming the list, looks like most extensions are for scraping or automating LinkedIn usage. Not surprising as there's money to be made with LinkedIn data. Scraping was a problem when I worked there, the abuse teams built some reasonably sophisticated detection & prevention, and it was a constant battle.
In order to create the data source that LinkedIn's extension-fingerprinting relies on to work, someone (at LinkedIn*?) almost certainly violated the Chrome Web Store TOS—by (perversely*) scraping it.
* if LinkedIn didn't take the data from an existing data source
a problem for linkedin != "a problem". The real problem for people is the back room data brokering linkedin and others do.
from the code doesn't look like they do anything if they have a match, they just save all the results to a csv for fingerprinting?
"The code" here you're referring to (fetch_extension_names.js[1]) isn't and doesn't claim to be LinkedIn's fingerprinting code. It's a scraper that the researcher behind this repo wrote in order to themselves create the CSV that they're publishing.
LinkedIn's fingerprinting code, as the README explains, is found in fingerprint.js[2], which embeds a big JSON literal with the IDs of the extensions it probes for. (Sickeningly enough, this data starts about two-thirds of the way through the file* and isn't the culprit behind the bulk of its 2.15 MB size…)
* the one (on line 34394) starting:
1. <https://github.com/mdp/linkedin-extension-fingerprinting/blo...>
2. <https://github.com/mdp/linkedin-extension-fingerprinting/blo...>
Wont someone think of poor little LinkedIn, a subsidiary of one of the largest data brokers in the world?
Why frame what you are trying to say like that? Businesses of all sizes deserve the ability to protect their businesses from abuse.
14 replies →
I mean, regardless of who they are or even if you don’t like what LinkedIn does themselves with the data people have given them, the random third parties with the extensions don’t additionally deserve to just grab all that data too, do they?
5 replies →
[dead]
I wrote an article about it a couple of months ago. I also explain why, how and a way to prevent it.
https://javascript.plainenglish.io/the-extensions-you-use-ar...
To clarify, you talk about why it's possible, not why LinkedIn is doing it, right? Or did I miss something in your article.
I can confirm.. open up linkedIn.. hit F12 and watch the error count keep going up and up and up
Screenshots found here https://x.com/DenisGobo/status/2018334684879438150
xcancel link: https://xcancel.com/DenisGobo/status/2018334684879438150
I wrote a blog post recently about the technique used by LinkedIn to do extension probing, as well as other ways to do it with less side effects
https://blog.castle.io/detecting-browser-extensions-for-bot-...
Setup a quick CDP connection. Have Claude Code attach and inject JS into Page.addScriptToEvaluateOnNewDocument. Loads before the page.
Typical early hooks: • fetch wrapper • XMLHttpRequest.prototype.open/send wrapper • WebSocket constructor wrapper • history.pushState/replaceState wrapper • EventTarget.addEventListener wrapper (optional, heavy) • MutationObserver for DOM diffs • Error + unhandledrejection capture
what would this do?
Only 16%!?
> This repository documents every extension LinkedIn checks for and provides tools to identify them.
I get that the CSV lists the extensions, and the tools are provided in order to show work (mapping IDs to actual software). But how was it determined that LinkedIn checks for extensions with these IDs?
And is this relevant for non-Chrome users?
Technical writeup from a few weeks ago by a vendor that explains how LinkedIn does it, then boasts that their approach is "quieter, harder to notice, and easier to run at scale":
https://blog.castle.io/detecting-browser-extensions-for-bot-...
I suggest everyone take a look at the list of extensions and their names for some very important context: https://github.com/mdp/linkedin-extension-fingerprinting/blo...
I didn't find popular extensions like uBlock or other ad blockers.
The list is full of scammy looking data collection and AI tools, though. Some random names from scrolling through the list:
- LinkedGPT: ChatGPT for LinkedIn
- Apollo Scraper - Extract & Export Apollo B2B Leads
- AI Social Media Assistant
- LinkedIn Engagement Assistant
- LinkedIn Lead Magnet
- LinkedIn Extraction Tool - OutreachSheet
- Highperformr AI - Phone Number and Email Finder
- AI Agent For Jobs
These look like the kind of tools scummy recruiters and sales people use to identify targets for mass spamming. I see several AI auto-application tools in there too.
Curious question: why would they check for installed extensions on one's browser?
Fingerprinting. There are a few reasons you'd do it:
1. Bot prevention. If the bots don't know that you're doing this, you might have a reliable bot detector for a while. The bots will quite possibly have no extensions at all, or even better specific exact combination they always use. Noticing bots means you can block them from scraping your site or spamming your users. If you wanna be very fancy, you could provide fake data or quietly ignore the stuff they create on the site.
2. Spamming/misuse evasion. Imagine an extension called "Send Messages to everybody with a given job role at this company." LinkedIn would prefer not to allow that, probably because they'd want to sell that feature.
3. User tracking.
most automations for sales and marketing use browser extensions... linkedIn wants you using their tools not 3rd party
Their own tools suck, that’s the issue.
For a social network, more information about their users = better ad targeting. It likely gets plumbed into models to inform user profiles.
Look at the actual list. It's primarily questionable AI tools, scrapers, lead generation tools, and other plugins in that vein.
I would guess this is for rate limiting and abuse detection.
An attempt at fingerprinting, I suppose?
Another thing... they alter the localStorage & sessionStorage prototype, by wrapping the native ones with a wrapper that prevent keys that not in their whitelist from being set.
You can try this by opening devtools and setting
See also: a demo page for the same technique that can enumerate many extensions installed in your browser: https://browserleaks.com/chrome
I’m probably on the list. I made a LinkedIn Redactor that allowed you to add keywords and remove posts from your thread that included such words. It’s the X feature but for LinkedIn. Anyway, got a cease and desist from those lame fucks at LI. So I removed from the chrome store but it’s still available on GitHub.
[removed]
That’s incorrect, it’s trying to load an asset (hardcoded unique per-extension path) for each extension, there is a huge list of these in the source code: https://raw.githubusercontent.com/mdp/linkedin-extension-fin...
This is a security vulnerability and should be patched. Sorry, LinkedIn.
(Alternatively extension developers can modify their extensions to block these requests!)
No kidding. I am shocked this works.
Does Firefox have a similar weakness?
3 replies →
I'm not sure how you'd patch that. Any request that’s made from the current open tab / window is made on behalf of the user. From my point of view, it's impossible for the browser to know, if the request is legit or not.
1 reply →
Is there no browser setting to defend against this attack? If not, there should be, versus relying on extension authors to configure or enable such a setting.
3 replies →
Looks to me like LinkedIn is fetching chrome-extension://{extension id}/{known filename} and seeing if it succeeds, not pinging the web store.
Should be patched nonetheless though, that's a pretty obscene fingerprinting vector.
How do you patch it? The extensions themselves (presumably) need to access the same web accessible resources from their content scripts. How do you differentiate between some extension’s content script requesting the resource and LinkedIn requesting it?
2 replies →
If this is true, it's insane that this would work:
- why does CWS respond to cross-site requests?
- why is chrome sending the credentials (or equivalent) in these requests?
- why is the button enabled server-side and not via JS? Google must be confident in knowing the exact and latest state of your installed extensions enough to store it on their servers, I guess
It's not true. The person you're responding to has a habit of posting implausible-but-plausibly-plausible nonsense, and that's not how this works at all.
Wouldn't that mean 2900 requests from fingerprint.js??
Isn't it enumerating web_accessible_resources? Below static collectFeatures(e, t) there is a mapping of extension IDs to files in the const r (Minified JS, obviously.)
Edit: Confirmed. It's not pinging the Chrome Web Store. https://blog.castle.io/detecting-browser-extensions-for-bot-...
[flagged]